Merge branch 'master' of https://github.com/FlaxEngine/FlaxEngine into indirect-vulkan

This commit is contained in:
Jean-Baptiste Perrier
2021-05-16 17:41:10 +02:00
551 changed files with 35146 additions and 5077 deletions

View File

@@ -8,15 +8,18 @@ jobs:
name: Editor (Linux, Development x64)
runs-on: "ubuntu-20.04"
steps:
- name: Install dependencies
run: |
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Checkout repo
uses: actions/checkout@v2
- name: Checkout LFS
run: |
git lfs version
git lfs pull
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/*
sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list
sudo apt-get update
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Build
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor

View File

@@ -0,0 +1,4 @@
deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse

BIN
Content/Editor/IconsAtlas.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -0,0 +1,23 @@
%copyright%
#pragma once
#include "Engine/Core/ISerializable.h"
#include "Engine/Core/Types/BaseTypes.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Scripting/ScriptingType.h"
/// <summary>
/// %class% Json Asset.
/// </summary>
API_CLASS() class %module%%class% : public ISerializable
{
API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE_NO_SPAWN(%class%);
public:
// Custom float value.
API_FIELD(Attributes = "Range(0, 20), EditorOrder(0), EditorDisplay(\"Data\")")
float FloatValue = 20.0f;
// Custom vector data.
API_FIELD(Attributes = "EditorOrder(1), EditorDisplay(\"Data\")")
Vector3 Vector3Value = Vector3(0.1f);
};

View File

@@ -0,0 +1,8 @@
%copyright%
#include "%filename%.h"
#include "Engine/Core/Log.h"
void %class%::RunNativeAction(Vector4 data)
{
LOG(Warning, "Data in RunNativeAction: {0}", data);
}

View File

@@ -0,0 +1,20 @@
%copyright%
#pragma once
#include "Engine/Scripting/Script.h"
#include "Engine/Core/Math/Vector4.h"
/// <summary>
/// %class% Function Library
/// </summary>
API_CLASS(Static) class %module%%class%
{
DECLARE_SCRIPTING_TYPE_MINIMAL(%class%);
public:
/// <summary>
/// Logs the function parameter natively.
/// </summary>
/// <param name="data">Data to pass to native code</param>
API_FUNCTION() static void RunNativeAction(Vector4 data);
};

View File

@@ -4,23 +4,30 @@ using FlaxEngine;
namespace %namespace%
{
/// <summary>
/// %class% Script.
/// </summary>
public class %class% : Script
{
/// <inheritdoc/>
public override void OnStart()
{
// Here you can add code that needs to be called when script is created, just before the first game update
}
/// <inheritdoc/>
public override void OnEnable()
{
// Here you can add code that needs to be called when script is enabled (eg. register for events)
}
/// <inheritdoc/>
public override void OnDisable()
{
// Here you can add code that needs to be called when script is disabled (eg. unregister from events)
}
/// <inheritdoc/>
public override void OnUpdate()
{
// Here you can add code that needs to be called every frame

BIN
Content/Shaders/BitonicSort.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/DepthOfField.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/EyeAdaptation.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GUI.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -5,6 +5,7 @@ Custom fork: [https://github.com/FlaxEngine/mono](https://github.com/FlaxEngine/
### Notes
Some useful notes and tips for devs:
* Use `-monolog` to print Mono logs to Flax logs
* When working with mono fork set `localRepoPath` to local repo location in `Source\Tools\Flax.Build\Deps\Dependencies\mono.cs`
* To update mono deps when developing/updating use `.\Development\Scripts\Windows\CallBuildTool.bat -log -ReBuildDeps -verbose -depsToBuild=mono -platform=Windows`, then build engine and run it
* `MONO_GC_DEBUG=check-remset-consistency` - it will do additional checks at each collection to see if there are any missing write barriers

View File

@@ -10,6 +10,7 @@
#include "Editor/Editor.h"
#include "Editor/ProjectInfo.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Utilities/StringConverter.h"
#include "FlaxEngine.Gen.h"

View File

@@ -53,6 +53,11 @@ namespace FlaxEditor.Content.Create
/// </summary>
NavigationSettings,
/// <summary>
/// The localization settings.
/// </summary>
LocalizationSettings,
/// <summary>
/// The build settings.
/// </summary>
@@ -108,6 +113,7 @@ namespace FlaxEditor.Content.Create
typeof(PhysicsSettings),
typeof(GraphicsSettings),
typeof(NavigationSettings),
typeof(LocalizationSettings),
typeof(BuildSettings),
typeof(InputSettings),
typeof(WindowsPlatformSettings),

View File

@@ -116,8 +116,7 @@ namespace FlaxEditor.Content.Import
if (FileTypes.TryGetValue(extension, out ImportFileEntryHandler createDelegate))
return createDelegate(ref request);
// Use default type
return request.IsBinaryAsset ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
return request.IsInBuilt ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
}
internal static void RegisterDefaultTypes()

View File

@@ -21,9 +21,9 @@ namespace FlaxEditor.Content.Import
public string OutputPath;
/// <summary>
/// Flag set to true for binary assets handled by the engine internally.
/// Flag set to true for the assets handled by the engine internally.
/// </summary>
public bool IsBinaryAsset;
public bool IsInBuilt;
/// <summary>
/// Flag used to skip showing import settings dialog to used. Can be used for importing assets from code by plugins.

View File

@@ -483,7 +483,9 @@ namespace FlaxEditor.Content.Import
{
if (settings is TextureImportSettings o)
{
var sprites = o.Sprites ?? _settings.Sprites; // Preserve sprites if not specified to override
_settings = o;
_settings.Sprites = sprites;
return true;
}
return false;

View File

@@ -20,6 +20,6 @@ namespace FlaxEditor.Content
}
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript128;
}
}

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.Content
public override bool Exists => Directory.Exists(Path);
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder128;
/// <inheritdoc />
internal override void UpdatePath(string value)

View File

@@ -455,7 +455,7 @@ namespace FlaxEditor.Content
const float thumbnailInShadowSize = 50.0f;
var shadowRect = rectangle.MakeExpanded((DefaultThumbnailSize - thumbnailInShadowSize) * rectangle.Width / DefaultThumbnailSize * 1.3f);
if (!_shadowIcon.IsValid)
_shadowIcon = Editor.Instance.Icons.AssetShadow;
_shadowIcon = Editor.Instance.Icons.AssetShadow128;
Render2D.DrawSprite(_shadowIcon, shadowRect);
}

View File

@@ -20,6 +20,6 @@ namespace FlaxEditor.Content
}
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CppScript64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128;
}
}

View File

@@ -26,6 +26,6 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
}
}

View File

@@ -11,6 +11,8 @@ namespace FlaxEditor.Content
/// <seealso cref="FlaxEditor.Content.AssetItem" />
public class JsonAssetItem : AssetItem
{
private readonly SpriteHandle _thumbnail;
/// <summary>
/// Initializes a new instance of the <see cref="JsonAssetItem"/> class.
/// </summary>
@@ -20,13 +22,27 @@ namespace FlaxEditor.Content
public JsonAssetItem(string path, Guid id, string typeName)
: base(path, typeName, ref id)
{
_thumbnail = Editor.Instance.Icons.Document128;
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonAssetItem"/> class.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="id">The identifier.</param>
/// <param name="typeName">Name of the resource type.</param>
/// <param name="thumbnail">Asset icon.</param>
public JsonAssetItem(string path, Guid id, string typeName, SpriteHandle thumbnail)
: base(path, typeName, ref id)
{
_thumbnail = thumbnail;
}
/// <inheritdoc />
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Json;
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
public override SpriteHandle DefaultThumbnail => _thumbnail;
/// <inheritdoc />
protected override bool DrawShadow => false;

View File

@@ -40,7 +40,7 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
/// <inheritdoc />
protected override bool DrawShadow => true;

View File

@@ -28,7 +28,7 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Scene;
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene128;
/// <inheritdoc />
public override bool IsOfType(Type type)

View File

@@ -27,6 +27,6 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Shader;
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
}
}

View File

@@ -539,7 +539,7 @@ namespace FlaxEditor.Content
}
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CodeScript64;
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128;
/// <inheritdoc />
protected override bool DrawShadow => false;

View File

@@ -76,7 +76,7 @@ void PreviewsCache::FlushTask::OnEnd()
ThreadPoolTask::OnEnd();
}
REGISTER_BINARY_ASSET(PreviewsCache, "FlaxEditor.PreviewsCache", ::New<TextureAssetUpgrader>(), false);
REGISTER_BINARY_ASSET_WITH_UPGRADER(PreviewsCache, "FlaxEditor.PreviewsCache", TextureAssetUpgrader, false);
PreviewsCache::PreviewsCache(const SpawnParams& params, const AssetInfo* info)
: SpriteAtlas(params, info)

View File

@@ -73,6 +73,16 @@ namespace FlaxEditor.Content
throw new NotImplementedException();
}
/// <summary>
/// Determines whether the specified filename is valid for this proxy.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns><c>true</c> if the filename is valid, otherwise <c>false</c>.</returns>
public virtual bool IsFileNameValid(string filename)
{
return true;
}
/// <summary>
/// Determines whether this proxy can create items in the specified target location.
/// </summary>

View File

@@ -0,0 +1,134 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.IO;
using System.Text;
using FlaxEditor.Content.Settings;
using FlaxEngine;
namespace FlaxEditor.Content
{
/// <summary>
/// Context proxy object for C++ files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
public abstract class CppProxy : ScriptProxy
{
/// <summary>
/// Gets the paths for header and source files to format.
/// </summary>
/// <param name="headerTemplate">The header template path.</param>
/// <param name="sourceTemplate">The source template path.</param>
protected abstract void GetTemplatePaths(out string headerTemplate, out string sourceTemplate);
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return false;
}
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{
// Find the module that this script is being added (based on the path)
var module = string.Empty;
var project = TryGetProjectAtFolder(outputPath, out var moduleName);
if (project != null)
{
module = moduleName.ToUpperInvariant() + "_API ";
}
var gameSettings = GameSettings.Load();
var scriptName = ScriptItem.CreateScriptName(outputPath);
var filename = Path.GetFileNameWithoutExtension(outputPath);
var copyrightComment = string.IsNullOrEmpty(gameSettings.CopyrightNotice) ? string.Empty : string.Format("// {0}{1}{1}", gameSettings.CopyrightNotice, Environment.NewLine);
GetTemplatePaths(out var headerTemplatePath, out var sourceTemplatePath);
if (headerTemplatePath != null)
{
var headerTemplate = File.ReadAllText(headerTemplatePath);
headerTemplate = headerTemplate.Replace("%copyright%", copyrightComment);
headerTemplate = headerTemplate.Replace("%class%", scriptName);
headerTemplate = headerTemplate.Replace("%module%", module);
headerTemplate = headerTemplate.Replace("%filename%", filename);
File.WriteAllText(Path.ChangeExtension(outputPath, ".h"), headerTemplate, Encoding.UTF8);
}
if (sourceTemplatePath != null)
{
var sourceTemplate = File.ReadAllText(sourceTemplatePath);
sourceTemplate = sourceTemplate.Replace("%copyright%", copyrightComment);
sourceTemplate = sourceTemplate.Replace("%class%", scriptName);
sourceTemplate = sourceTemplate.Replace("%module%", module);
sourceTemplate = sourceTemplate.Replace("%filename%", filename);
File.WriteAllText(outputPath, sourceTemplate, Encoding.UTF8);
}
}
/// <inheritdoc />
public override string FileExtension => "cpp";
/// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x9c1c9c);
}
/// <summary>
/// Context proxy object for C++ script files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
public class CppScriptProxy : CppProxy
{
/// <inheritdoc />
public override string Name => "C++ Script";
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return item is CppScriptItem;
}
/// <inheritdoc />
protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
{
headerTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.h");
sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.cpp");
}
}
/// <summary>
/// Context proxy object for C++ Json Asset files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
public class CppStaticClassProxy : CppProxy
{
/// <inheritdoc />
public override string Name => "C++ Function Library";
/// <inheritdoc />
protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
{
headerTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppStaticClassTemplate.h");
sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppStaticClassTemplate.cpp");
}
}
/// <summary>
/// Context proxy object for C++ Json Asset files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
public class CppAssetProxy : CppProxy
{
/// <inheritdoc />
public override string Name => "C++ Json Asset";
/// <inheritdoc />
protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
{
headerTemplate = null;
sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppAssetTemplate.h");
//sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppAssetTemplate.cpp");
}
/// <inheritdoc />
public override string FileExtension => "h";
}
}

View File

@@ -1,65 +0,0 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.IO;
using System.Text;
using FlaxEditor.Content.Settings;
using FlaxEngine;
namespace FlaxEditor.Content
{
/// <summary>
/// Context proxy object for C++ script files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
public class CppScriptProxy : ScriptProxy
{
/// <inheritdoc />
public override string Name => "C++ Script";
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return item is CppScriptItem;
}
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{
// Load templates
var headerTemplate = File.ReadAllText(StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.h"));
var sourceTemplate = File.ReadAllText(StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.cpp"));
// Find the module that this script is being added (based on the path)
var module = string.Empty;
var project = TryGetProjectAtFolder(outputPath, out var moduleName);
if (project != null)
{
module = moduleName.ToUpperInvariant() + "_API ";
}
// Format
var gameSettings = GameSettings.Load();
var scriptName = ScriptItem.CreateScriptName(outputPath);
var filename = Path.GetFileNameWithoutExtension(outputPath);
var copyrightComment = string.IsNullOrEmpty(gameSettings.CopyrightNotice) ? string.Empty : string.Format("// {0}{1}{1}", gameSettings.CopyrightNotice, Environment.NewLine);
headerTemplate = headerTemplate.Replace("%copyright%", copyrightComment);
headerTemplate = headerTemplate.Replace("%class%", scriptName);
headerTemplate = headerTemplate.Replace("%module%", module);
sourceTemplate = sourceTemplate.Replace("%filename%", filename);
sourceTemplate = sourceTemplate.Replace("%copyright%", copyrightComment);
sourceTemplate = sourceTemplate.Replace("%class%", scriptName);
sourceTemplate = sourceTemplate.Replace("%filename%", filename);
// Save
File.WriteAllText(Path.ChangeExtension(outputPath, ".h"), headerTemplate, Encoding.UTF8);
File.WriteAllText(outputPath, sourceTemplate, Encoding.UTF8);
}
/// <inheritdoc />
public override string FileExtension => "cpp";
/// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x9c1c9c);
}
}

View File

@@ -2,7 +2,6 @@
using System;
using FlaxEditor.Content.Create;
using FlaxEditor.Content.Settings;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Windows;
@@ -45,18 +44,12 @@ namespace FlaxEditor.Content
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return item is JsonAssetItem;
return item is JsonAssetItem json && json.TypeName == TypeName;
}
/// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0xd14f67);
/// <inheritdoc />
public override bool AcceptsAsset(string typeName, string path)
{
return typeName == TypeName && base.AcceptsAsset(typeName, path);
}
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
@@ -143,6 +136,12 @@ namespace FlaxEditor.Content
return path.EndsWith(FileExtension, StringComparison.OrdinalIgnoreCase);
}
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return item is JsonAssetItem;
}
/// <inheritdoc />
public override bool CanCreate(ContentFolder targetLocation)
{

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
namespace FlaxEditor.Content
{
/// <summary>
/// <see cref="LocalizedStringTable"/> proxy.
/// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetProxy" />
public class LocalizedStringTableProxy : JsonAssetProxy
{
/// <inheritdoc />
public override EditorWindow Open(Editor editor, ContentItem item)
{
return new LocalizedStringTableWindow(editor, (JsonAssetItem)item);
}
/// <inheritdoc />
public override string TypeName => "FlaxEngine.LocalizedStringTable";
}
}

View File

@@ -66,6 +66,15 @@ namespace FlaxEditor.Content
return false;
}
/// <inheritdoc />
public override bool IsFileNameValid(string filename)
{
// Scripts cannot start with digit.
if (Char.IsDigit(filename[0]))
return false;
return true;
}
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{

View File

@@ -3,6 +3,7 @@
using System;
using FlaxEditor.Content.Create;
using FlaxEditor.Content.Settings;
using FlaxEngine;
namespace FlaxEditor.Content
{
@@ -13,15 +14,18 @@ namespace FlaxEditor.Content
public sealed class SettingsProxy : JsonAssetProxy
{
private readonly Type _type;
private readonly SpriteHandle _thumbnail;
/// <summary>
/// Initializes a new instance of the <see cref="SettingsProxy"/> class.
/// </summary>
/// <param name="type">The settings asset type (must be subclass of SettingsBase type).</param>
public SettingsProxy(Type type)
/// <param name="thumbnail">Asset icon.</param>
public SettingsProxy(Type type, SpriteHandle thumbnail)
{
_type = type;
TypeName = type.FullName;
_thumbnail = thumbnail;
}
/// <inheritdoc />
@@ -44,6 +48,12 @@ namespace FlaxEditor.Content
Editor.Instance.ContentImporting.Create(new SettingsCreateEntry(outputPath));
}
/// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
return new JsonAssetItem(path, id, typeName, _thumbnail);
}
/// <inheritdoc />
public override bool IsProxyFor<T>()
{

View File

@@ -77,7 +77,7 @@ namespace FlaxEditor.Content
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
protected ContentTreeNode(ContentTreeNode parent, ContentFolderType type, string path)
: base(false, Editor.Instance.Icons.FolderClosed12, Editor.Instance.Icons.FolderOpened12)
: base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;

View File

@@ -7,6 +7,7 @@
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/HashSet.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Core/Types/Guid.h"
class GameCooker;
class PlatformTools;

View File

@@ -10,6 +10,7 @@
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Content/Content.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Threading/ThreadSpawner.h"
#include "Engine/Platform/FileSystem.h"
#include "Steps/ValidateStep.h"

View File

@@ -29,6 +29,7 @@
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Engine/Base/GameBase.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Tools/TextureTool/TextureTool.h"
#if PLATFORM_TOOLS_WINDOWS
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"

View File

@@ -7,6 +7,7 @@
#include "Engine/Core/Config/GameSettings.h"
#include "Engine/Renderer/ReflectionsPass.h"
#include "Engine/Renderer/AntiAliasing/SMAA.h"
#include "Engine/Engine/Globals.h"
bool DeployDataStep::Perform(CookingData& data)
{

View File

@@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors
/// <inheritdoc />
protected override void OnModified()
{
Presenter.Modified?.Invoke();
Presenter.OnModified();
base.OnModified();
}
@@ -354,6 +354,14 @@ namespace FlaxEditor.CustomEditors
ExpandGroups(this, false);
}
/// <summary>
/// Invokes <see cref="Modified"/> event.
/// </summary>
public void OnModified()
{
Modified?.Invoke();
}
/// <summary>
/// Called when selection gets changed.
/// </summary>

View File

@@ -3,6 +3,7 @@
#include "CustomEditorsUtil.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Scripting/Scripting.h"

View File

@@ -0,0 +1,429 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using FlaxEditor.Content.Settings;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Object = FlaxEngine.Object;
namespace FlaxEditor.CustomEditors.Dedicated
{
[CustomEditor(typeof(LocalizationSettings))]
sealed class LocalizationSettingsEditor : GenericEditor
{
private CultureInfo _theMostTranslatedCulture;
private int _theMostTranslatedCultureCount;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
Profiler.BeginEvent("LocalizationSettingsEditor.Initialize");
var settings = (LocalizationSettings)Values[0];
var tablesLength = settings.LocalizedStringTables?.Length ?? 0;
var tables = new List<LocalizedStringTable>(tablesLength);
for (int i = 0; i < tablesLength; i++)
{
var table = settings.LocalizedStringTables[i];
if (table && !table.WaitForLoaded())
tables.Add(table);
}
var locales = tables.GroupBy(x => x.Locale);
var tableEntries = new Dictionary<LocalizedStringTable, Dictionary<string, string[]>>();
var allKeys = new HashSet<string>();
foreach (var e in locales)
{
foreach (var table in e)
{
var entries = table.Entries;
tableEntries[table] = entries;
allKeys.AddRange(entries.Keys);
}
}
{
var group = layout.Group("Preview");
// Current language and culture preview management
group.Object("Current Language", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentLanguage, (instance, index) => Localization.CurrentLanguage, (instance, index, value) => Localization.CurrentLanguage = value as CultureInfo), null, "Current UI display language for the game preview.");
group.Object("Current Culture", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentCulture, (instance, index) => Localization.CurrentCulture, (instance, index, value) => Localization.CurrentCulture = value as CultureInfo), null, "Current values formatting culture for the game preview.");
}
{
var group = layout.Group("Locales");
// Show all existing locales
_theMostTranslatedCulture = null;
_theMostTranslatedCultureCount = -1;
foreach (var e in locales)
{
var culture = new CultureInfo(e.Key);
var prop = group.AddPropertyItem(CultureInfoEditor.GetName(culture), culture.NativeName);
int count = e.Sum(x => tableEntries[x].Count);
int validCount = e.Sum(x => tableEntries[x].Values.Count(y => y != null && y.Length != 0 && !string.IsNullOrEmpty(y[0])));
if (count > _theMostTranslatedCultureCount)
{
_theMostTranslatedCulture = culture;
_theMostTranslatedCultureCount = count;
}
prop.Label(string.Format("Progress: {0}% ({1}/{2})", (int)(((float)validCount / allKeys.Count * 100.0f)), validCount, allKeys.Count));
prop.Label("Tables:");
foreach (var table in e)
{
var namePath = table.Path;
if (namePath.StartsWith(Globals.ProjectFolder))
namePath = namePath.Substring(Globals.ProjectFolder.Length + 1);
var tableLabel = prop.ClickableLabel(namePath).CustomControl;
tableLabel.TextColorHighlighted = Color.Wheat;
tableLabel.DoubleClick += delegate { Editor.Instance.Windows.ContentWin.Select(table); };
}
group.Space(10);
}
// Update add button
var update = group.Button("Update").Button;
update.TooltipText = "Refreshes the dashboard statistics";
update.Height = 16.0f;
update.Clicked += RebuildLayout;
// New locale add button
var addLocale = group.Button("Add Locale...").Button;
addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables";
addLocale.Height = 16.0f;
addLocale.ButtonClicked += delegate(Button button)
{
var menu = CultureInfoEditor.CreatePicker(null, culture =>
{
var displayName = CultureInfoEditor.GetName(culture);
if (locales.Any(x => x.Key == culture.Name))
{
MessageBox.Show($"Culture '{displayName}' is already added.");
return;
}
Profiler.BeginEvent("LocalizationSettingsEditor.AddLocale");
Editor.Log($"Adding culture '{displayName}' to localization settings");
var newTables = settings.LocalizedStringTables.ToList();
if (_theMostTranslatedCulture != null)
{
// Duplicate localization for culture with the highest amount of keys
var g = locales.First(x => x.Key == _theMostTranslatedCulture.Name);
foreach (var e in g)
{
var path = e.Path;
var filename = Path.GetFileNameWithoutExtension(path);
if (filename.EndsWith(_theMostTranslatedCulture.Name))
filename = filename.Substring(0, filename.Length - _theMostTranslatedCulture.Name.Length);
path = Path.Combine(Path.GetDirectoryName(path), filename + culture.Name + ".json");
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
table.Locale = culture.Name;
var entries = new Dictionary<string, string[]>();
foreach (var ee in tableEntries[e])
{
var vv = (string[])ee.Value.Clone();
for (var i = 0; i < vv.Length; i++)
vv[i] = string.Empty;
entries.Add(ee.Key, vv);
}
table.Entries = entries;
if (!table.Save(path))
{
Object.Destroy(table);
newTables.Add(FlaxEngine.Content.LoadAsync<LocalizedStringTable>(path));
}
}
}
else
{
// No localization so initialize with empty table
var path = Path.Combine(Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization", culture.Name + ".json"));
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
table.Locale = culture.Name;
if (!table.Save(path))
{
Object.Destroy(table);
newTables.Add(FlaxEngine.Content.LoadAsync<LocalizedStringTable>(path));
}
}
settings.LocalizedStringTables = newTables.ToArray();
Presenter.OnModified();
RebuildLayout();
Profiler.EndEvent();
});
menu.Show(button, new Vector2(0, button.Height));
};
// Export button
var exportLocalization = group.Button("Export...").Button;
exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
exportLocalization.Height = 16.0f;
exportLocalization.Clicked += delegate
{
if (FileSystem.ShowSaveFileDialog(null, null, "*.pot", false, "Export localization for translation to .pot file", out var filenames))
return;
Profiler.BeginEvent("LocalizationSettingsEditor.Export");
if (!filenames[0].EndsWith(".pot"))
filenames[0] += ".pot";
var nplurals = 1;
foreach (var e in tableEntries)
{
foreach (var value in e.Value.Values)
{
if (value != null && value.Length > nplurals)
nplurals = value.Length;
}
}
using (var writer = new StreamWriter(filenames[0], false, Encoding.UTF8))
{
writer.WriteLine("msgid \"\"");
writer.WriteLine("msgstr \"\"");
writer.WriteLine("\"Language: English\\n\"");
writer.WriteLine("\"MIME-Version: 1.0\\n\"");
writer.WriteLine("\"Content-Type: text/plain; charset=UTF-8\\n\"");
writer.WriteLine("\"Content-Transfer-Encoding: 8bit\\n\"");
writer.WriteLine($"\"Plural-Forms: nplurals={nplurals}; plural=(n != 1);\\n\"");
writer.WriteLine("\"X-Generator: FlaxEngine\\n\"");
var written = new HashSet<string>();
foreach (var e in tableEntries)
{
foreach (var pair in e.Value)
{
if (written.Contains(pair.Key))
continue;
written.Add(pair.Key);
writer.WriteLine("");
writer.WriteLine($"msgid \"{pair.Key}\"");
if (pair.Value == null || pair.Value.Length < 2)
{
writer.WriteLine("msgstr \"\"");
}
else
{
writer.WriteLine("msgid_plural \"\"");
for (int i = 0; i < pair.Value.Length; i++)
writer.WriteLine($"msgstr[{i}] \"\"");
}
}
if (written.Count == allKeys.Count)
break;
}
}
Profiler.EndEvent();
};
// Find localized strings in code button
var findStringsCode = group.Button("Find localized strings in code").Button;
findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files";
findStringsCode.Height = 16.0f;
findStringsCode.Clicked += delegate
{
var newKeys = new Dictionary<string, string>();
Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInSource");
// C#
var files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cs", SearchOption.AllDirectories);
var filesCount = files.Length;
foreach (var file in files)
FindNewKeysCSharp(file, newKeys, allKeys);
// C++
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories);
filesCount += files.Length;
foreach (var file in files)
FindNewKeysCpp(file, newKeys, allKeys);
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories);
filesCount += files.Length;
foreach (var file in files)
FindNewKeysCpp(file, newKeys, allKeys);
AddNewKeys(newKeys, filesCount, locales, tableEntries);
Profiler.EndEvent();
};
// Find localized strings in content button
var findStringsContent = group.Button("Find localized strings in content").Button;
findStringsContent.TooltipText = "Searches for localized string usage in inside a project content files (scenes, prefabs)";
findStringsContent.Height = 16.0f;
findStringsContent.Clicked += delegate
{
var newKeys = new Dictionary<string, string>();
Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInContent");
// Scenes
var files = Directory.GetFiles(Globals.ProjectContentFolder, "*.scene", SearchOption.AllDirectories);
var filesCount = files.Length;
foreach (var file in files)
FindNewKeysJson(file, newKeys, allKeys);
// Prefabs
files = Directory.GetFiles(Globals.ProjectContentFolder, "*.prefab", SearchOption.AllDirectories);
filesCount += files.Length;
foreach (var file in files)
FindNewKeysJson(file, newKeys, allKeys);
AddNewKeys(newKeys, filesCount, locales, tableEntries);
Profiler.EndEvent();
};
}
{
// Raw asset data editing
var group = layout.Group("Data");
base.Initialize(group);
}
Profiler.EndEvent();
}
private static void FindNewKeysCSharp(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
{
var startToken = "Localization.GetString";
var textToken = "\"";
FindNewKeys(file, newKeys, allKeys, startToken, textToken);
}
private static void FindNewKeysCpp(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
{
var startToken = "Localization::GetString";
var textToken = "TEXT(\"";
FindNewKeys(file, newKeys, allKeys, startToken, textToken);
}
private static void FindNewKeys(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys, string startToken, string textToken)
{
var contents = File.ReadAllText(file);
var idx = contents.IndexOf(startToken);
while (idx != -1)
{
idx += startToken.Length + 1;
int braces = 1;
int start = idx;
while (idx < contents.Length && braces != 0)
{
if (contents[idx] == '(')
braces++;
if (contents[idx] == ')')
braces--;
idx++;
}
if (idx == contents.Length)
break;
var inside = contents.Substring(start, idx - start - 1);
var textStart = inside.IndexOf(textToken);
if (textStart != -1)
{
textStart += textToken.Length;
var textEnd = textStart;
while (textEnd < inside.Length && inside[textEnd] != '\"')
{
if (inside[textEnd] == '\\')
textEnd++;
textEnd++;
}
var id = inside.Substring(textStart, textEnd - textStart);
textStart = inside.Length > textEnd + 2 ? inside.IndexOf(textToken, textEnd + 2) : -1;
string value = null;
if (textStart != -1)
{
textStart += textToken.Length;
textEnd = textStart;
while (textEnd < inside.Length && inside[textEnd] != '\"')
{
if (inside[textEnd] == '\\')
textEnd++;
textEnd++;
}
value = inside.Substring(textStart, textEnd - textStart);
}
if (!allKeys.Contains(id))
newKeys[id] = value;
}
idx = contents.IndexOf(startToken, idx);
}
}
private static void FindNewKeysJson(Dictionary<string, string> newKeys, HashSet<string> allKeys, JToken token)
{
if (token is JObject o)
{
foreach (var p in o)
{
if (string.Equals(p.Key, "Id", StringComparison.Ordinal) && p.Value is JValue i && i.Value is string id && !allKeys.Contains(id))
{
var count = o.Properties().Count();
if (count == 1)
{
newKeys[id] = null;
return;
}
if (count == 2)
{
var v = o.Property("Value")?.Value as JValue;
if (v?.Value is string value)
{
newKeys[id] = value;
return;
}
}
}
FindNewKeysJson(newKeys, allKeys, p.Value);
}
}
else if (token is JArray a)
{
foreach (var p in a)
{
FindNewKeysJson(newKeys, allKeys, p);
}
}
}
private static void FindNewKeysJson(string file, Dictionary<string, string> newKeys, HashSet<string> allKeys)
{
using (var reader = new StreamReader(file))
using (var jsonReader = new JsonTextReader(reader))
{
var token = JToken.ReadFrom(jsonReader);
FindNewKeysJson(newKeys, allKeys, token);
}
}
private void AddNewKeys(Dictionary<string, string> newKeys, int filesCount, IEnumerable<IGrouping<string, LocalizedStringTable>> locales, Dictionary<LocalizedStringTable, Dictionary<string, string[]>> tableEntries)
{
Editor.Log($"Found {newKeys.Count} new localized strings in {filesCount} files");
if (newKeys.Count == 0)
return;
foreach (var e in newKeys)
Editor.Log(e.Key + (e.Value != null ? " = " + e.Value : string.Empty));
foreach (var locale in locales)
{
var table = locale.First();
var entries = tableEntries[table];
if (table.Locale == "en")
{
foreach (var e in newKeys)
entries[e.Key] = new[] { e.Value };
}
else
{
foreach (var e in newKeys)
entries[e.Key] = new[] { string.Empty };
}
table.Entries = entries;
table.Save();
}
RebuildLayout();
}
}
}

View File

@@ -154,9 +154,20 @@ namespace FlaxEditor.CustomEditors.Editors
if (i != 0 && spacing > 0f)
{
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
{
if (propertiesListElement.Labels.Count > 0)
{
var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
var margin = label.Margin;
margin.Bottom += spacing;
label.Margin = margin;
}
propertiesListElement.Space(spacing);
}
else
{
layout.Space(spacing);
}
}
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;

View File

@@ -0,0 +1,164 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Editors
{
/// <summary>
/// Default implementation of the inspector used to edit <see cref="CultureInfo"/> value type properties. Supports editing property of <see cref="string"/> type (as culture name).
/// </summary>
[CustomEditor(typeof(CultureInfo)), DefaultEditor]
internal class CultureInfoEditor : CustomEditor
{
private ClickableLabel _label;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
_label = layout.ClickableLabel(GetName(Culture)).CustomControl;
_label.RightClick += ShowPicker;
var button = new Button
{
Width = 16.0f,
Text = "...",
Parent = _label,
};
button.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
button.Clicked += ShowPicker;
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
_label.Text = GetName(Culture);
}
/// <inheritdoc />
protected override void Deinitialize()
{
_label = null;
base.Deinitialize();
}
private CultureInfo Culture
{
get
{
if (Values[0] is CultureInfo asCultureInfo)
return asCultureInfo;
if (Values[0] is string asString)
return new CultureInfo(asString);
return null;
}
set
{
if (Values[0] is CultureInfo)
SetValue(value);
else if (Values[0] is string)
SetValue(value.Name);
}
}
private class CultureInfoComparer : IComparer<CultureInfo>
{
public int Compare(CultureInfo a, CultureInfo b)
{
return string.Compare(a.Name, b.Name, StringComparison.Ordinal);
}
}
private static void UpdateFilter(TreeNode node, string filterText)
{
// Update children
bool isAnyChildVisible = false;
for (int i = 0; i < node.Children.Count; i++)
{
if (node.Children[i] is TreeNode child)
{
UpdateFilter(child, filterText);
isAnyChildVisible |= child.Visible;
}
}
// Update itself
bool noFilter = string.IsNullOrWhiteSpace(filterText);
bool isThisVisible = noFilter || QueryFilterHelper.Match(filterText, node.Text);
bool isExpanded = isAnyChildVisible;
if (isExpanded)
node.Expand(true);
else
node.Collapse(true);
node.Visible = isThisVisible | isAnyChildVisible;
}
private void ShowPicker()
{
var menu = CreatePicker(Culture, value => { Culture = value; });
menu.Show(_label, new Vector2(0, _label.Height));
}
internal static ContextMenuBase CreatePicker(CultureInfo value, Action<CultureInfo> changed)
{
var menu = Utilities.Utils.CreateSearchPopup(out var searchBox, out var tree);
tree.Margin = new Margin(-16.0f, 0.0f, -16.0f, -0.0f); // Hide root node
var root = tree.AddChild<TreeNode>();
var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
Array.Sort(cultures, 1, cultures.Length - 2, new CultureInfoComparer()); // at 0 there is Invariant Culture
var lcidToNode = new Dictionary<int, ContainerControl>();
for (var i = 0; i < cultures.Length; i++)
{
var culture = cultures[i];
var node = new TreeNode
{
Tag = culture,
Text = GetName(culture),
};
if (!lcidToNode.TryGetValue(culture.Parent.LCID, out ContainerControl parent))
parent = root;
node.Parent = parent;
lcidToNode[culture.LCID] = node;
}
if (value != null)
tree.Select((TreeNode)lcidToNode[value.LCID]);
tree.SelectedChanged += delegate(List<TreeNode> before, List<TreeNode> after)
{
if (after.Count == 1)
{
menu.Hide();
changed((CultureInfo)after[0].Tag);
}
};
searchBox.TextChanged += delegate
{
if (tree.IsLayoutLocked)
return;
root.LockChildrenRecursive();
var query = searchBox.Text;
UpdateFilter(root, query);
root.UnlockChildrenRecursive();
menu.PerformLayout();
};
root.ExpandAll(true);
return menu;
}
internal static string GetName(CultureInfo value)
{
return value != null ? string.Format("{0} - {1}", value.Name, value.EnglishName) : null;
}
}
}

View File

@@ -61,7 +61,7 @@ namespace FlaxEditor.CustomEditors.Editors
var keyType = _editor.Values.Type.GetGenericArguments()[0];
if (keyType == typeof(string) || keyType.IsPrimitive)
{
var popup = RenamePopup.Show(Parent, Bounds, Text, false);
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
popup.Validate += (renamePopup, value) =>
{
object newKey;
@@ -86,7 +86,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
else if (keyType.IsEnum)
{
var popup = RenamePopup.Show(Parent, Bounds, Text, false);
var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
var picker = new EnumComboBox(keyType)
{
AnchorPreset = AnchorPresets.StretchAll,
@@ -220,9 +220,20 @@ namespace FlaxEditor.CustomEditors.Editors
if (i != 0 && spacing > 0f)
{
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
{
if (propertiesListElement.Labels.Count > 0)
{
var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
var margin = label.Margin;
margin.Bottom += spacing;
label.Margin = margin;
}
propertiesListElement.Space(spacing);
}
else
{
layout.Space(spacing);
}
}
var key = keys.ElementAt(i);

View File

@@ -9,7 +9,7 @@ using FlaxEngine;
namespace FlaxEditor.CustomEditors.Editors
{
/// <summary>
/// Default implementation of the inspector used to edit float value type properties.
/// Default implementation of the inspector used to edit enum value type properties.
/// </summary>
[CustomEditor(typeof(Enum)), DefaultEditor]
public class EnumEditor : CustomEditor

View File

@@ -214,6 +214,7 @@ namespace FlaxEditor.CustomEditors.Editors
public ScriptMemberInfo Target;
public ScriptMemberInfo Source;
public PropertiesListElement PropertiesList;
public GroupElement Group;
public bool Invert;
public int LabelIndex;
@@ -257,15 +258,15 @@ namespace FlaxEditor.CustomEditors.Editors
for (int i = 0; i < properties.Length; i++)
{
var p = properties[i];
var attributes = p.GetAttributes(true);
var showInEditor = attributes.Any(x => x is ShowInEditorAttribute);
// Skip properties without getter or setter
if (!p.HasGet || !p.HasSet)
if (!p.HasGet || (!p.HasSet && !showInEditor))
continue;
var attributes = p.GetAttributes(true);
// Skip hidden fields, handle special attributes
if ((!p.IsPublic && !attributes.Any(x => x is ShowInEditorAttribute)) || attributes.Any(x => x is HideInEditorAttribute))
if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute))
continue;
items.Add(new ItemInfo(p, attributes));
@@ -379,26 +380,22 @@ namespace FlaxEditor.CustomEditors.Editors
}
}
}
if (item.VisibleIf != null)
if (item.VisibleIf != null && itemLayout.Children.Count > 0)
{
PropertiesListElement list;
if (itemLayout.Children.Count > 0 && itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
{
PropertiesListElement list = null;
GroupElement group = null;
if (itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
list = list1;
}
else if (itemLayout.Children[itemLayout.Children.Count - 1] is GroupElement group1)
group = group1;
else
{
// TODO: support inlined objects hiding?
return;
}
// Get source member used to check rule
var sourceMember = GetVisibleIfSource(item.Info.DeclaringType, item.VisibleIf);
if (sourceMember == ScriptType.Null)
return;
// Find the target control to show/hide
// Resize cache
if (_visibleIfCaches == null)
_visibleIfCaches = new VisibleIfCache[8];
@@ -414,6 +411,7 @@ namespace FlaxEditor.CustomEditors.Editors
Target = item.Info,
Source = sourceMember,
PropertiesList = list,
Group = group,
LabelIndex = labelIndex,
Invert = item.VisibleIf.Invert,
};
@@ -569,8 +567,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
for (int i = 0; i < _visibleIfCaches.Length; i++)
{
var c = _visibleIfCaches[i];
ref var c = ref _visibleIfCaches[i];
if (c.Target == ScriptMemberInfo.Null)
break;
@@ -586,7 +583,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
// Apply the visibility (note: there may be no label)
if (c.LabelIndex != -1 && c.PropertiesList.Labels.Count > c.LabelIndex)
if (c.LabelIndex != -1 && c.PropertiesList != null && c.PropertiesList.Labels.Count > c.LabelIndex)
{
var label = c.PropertiesList.Labels[c.LabelIndex];
label.Visible = visible;
@@ -599,6 +596,10 @@ namespace FlaxEditor.CustomEditors.Editors
child.Visible = visible;
}
}
if (c.Group != null)
{
c.Group.Panel.Visible = visible;
}
}
}
catch (Exception ex)

View File

@@ -0,0 +1,234 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Content.Settings;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Editors
{
/// <summary>
/// Default implementation of the inspector used to edit localized string properties.
/// </summary>
[CustomEditor(typeof(LocalizedString)), DefaultEditor]
public sealed class LocalizedStringEditor : GenericEditor
{
private TextBoxElement _idElement, _valueElement;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
if (layout.Children.Count == 0)
return;
var propList = layout.Children[layout.Children.Count - 1] as PropertiesListElement;
if (propList == null || propList.Children.Count != 2)
return;
var idElement = propList.Children[0] as TextBoxElement;
var valueElement = propList.Children[1] as TextBoxElement;
if (idElement == null || valueElement == null)
return;
_idElement = idElement;
_valueElement = valueElement;
var attributes = Values.GetAttributes();
var multiLine = attributes?.FirstOrDefault(x => x is MultilineTextAttribute);
if (multiLine != null)
{
valueElement.TextBox.IsMultiline = true;
valueElement.TextBox.Height *= 3;
}
var selectString = new Button
{
Width = 16.0f,
Text = "...",
TooltipText = "Select localized text from Localization Settings...",
Parent = idElement.TextBox,
};
selectString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
selectString.ButtonClicked += OnSelectStringClicked;
var addString = new Button
{
Width = 16.0f,
Text = "+",
TooltipText = "Add new localized text to Localization Settings (all used locales)",
Parent = _valueElement.TextBox,
Enabled = IsSingleObject,
};
addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
addString.ButtonClicked += OnAddStringClicked;
}
/// <inheritdoc />
internal override void RefreshInternal()
{
base.RefreshInternal();
if (_valueElement != null)
{
_valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text);
}
}
/// <inheritdoc />
protected override void Deinitialize()
{
base.Deinitialize();
_idElement = null;
_valueElement = null;
}
private void OnSelectStringClicked(Button button)
{
var settings = GameSettings.Load<LocalizationSettings>();
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
{
MessageBox.Show("No valid localization settings setup.");
return;
}
Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked");
var allKeys = new HashSet<string>();
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
{
var table = settings.LocalizedStringTables[i];
if (table && !table.WaitForLoaded())
{
var entries = table.Entries;
foreach (var e in entries)
allKeys.Add(e.Key);
}
}
var allKeysSorted = allKeys.ToList();
allKeysSorted.Sort();
var value = _idElement?.TextBox.Text;
var menu = Utils.CreateSearchPopup(out var searchBox, out var tree);
var idToNode = new TreeNode[allKeysSorted.Count];
for (var i = 0; i < allKeysSorted.Count; i++)
{
var key = allKeysSorted[i];
var node = new TreeNode
{
Text = key,
TooltipText = Localization.GetString(key),
Parent = tree,
};
if (key == value)
tree.Select(node);
idToNode[i] = node;
}
tree.SelectedChanged += delegate(List<TreeNode> before, List<TreeNode> after)
{
if (after.Count == 1)
{
menu.Hide();
_idElement.TextBox.SetTextAsUser(after[0].Text);
}
};
searchBox.TextChanged += delegate
{
if (tree.IsLayoutLocked)
return;
tree.LockChildrenRecursive();
var query = searchBox.Text;
for (int i = 0; i < idToNode.Length; i++)
{
var node = idToNode[i];
node.Visible = string.IsNullOrWhiteSpace(query) || QueryFilterHelper.Match(query, node.Text);
}
tree.UnlockChildrenRecursive();
menu.PerformLayout();
};
menu.Show(button, new Vector2(0, button.Height));
Profiler.EndEvent();
}
private void OnAddStringClicked(Button button)
{
var settings = GameSettings.Load<LocalizationSettings>();
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
{
MessageBox.Show("No valid localization settings setup.");
return;
}
Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked");
var allKeys = new HashSet<string>();
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
{
var table = settings.LocalizedStringTables[i];
if (table && !table.WaitForLoaded())
{
var entries = table.Entries;
foreach (var e in entries)
allKeys.Add(e.Key);
}
}
_valueElement.TextBox.SetTextAsUser(null);
string newKey = null;
if (string.IsNullOrEmpty(_idElement.Text))
{
CustomEditor customEditor = this;
while (customEditor?.Values != null)
{
if (customEditor.Values.Info != ScriptMemberInfo.Null)
if (newKey == null)
newKey = customEditor.Values.Info.Name;
else
newKey = customEditor.Values.Info.Name + '.' + newKey;
else if (customEditor.Values[0] is SceneObject sceneObject)
if (newKey == null)
newKey = sceneObject.GetNamePath('.');
else
newKey = sceneObject.GetNamePath('.') + '.' + newKey;
else
break;
customEditor = customEditor.ParentEditor;
}
if (string.IsNullOrWhiteSpace(newKey))
newKey = Guid.NewGuid().ToString("N");
}
else
{
newKey = _idElement.Text;
}
if (allKeys.Contains(newKey))
{
Profiler.EndEvent();
if (_idElement.Text != newKey)
_idElement.TextBox.SetTextAsUser(newKey);
else
MessageBox.Show("Already added.");
return;
}
var newValue = _valueElement.Text;
Editor.Log(newKey + (newValue != null ? " = " + newValue : string.Empty));
var locales = settings.LocalizedStringTables.GroupBy(x => x.Locale);
foreach (var locale in locales)
{
var table = locale.First();
var entries = table.Entries;
if (table.Locale == "en")
entries[newKey] = new[] { newValue };
else
entries[newKey] = new[] { string.Empty };
table.Entries = entries;
table.Save();
}
_idElement.TextBox.SetTextAsUser(newKey);
Profiler.EndEvent();
}
}
}

View File

@@ -3,7 +3,6 @@
using System;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEngine;
namespace FlaxEditor.CustomEditors.Editors
{

View File

@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Elements
{
/// <summary>
/// The vertical panel element.
/// The horizontal panel element.
/// </summary>
/// <seealso cref="FlaxEditor.CustomEditors.LayoutElement" />
public class VerticalPanelElement : LayoutElementsContainer
public class HorizontalPanelElement : LayoutElementsContainer
{
/// <summary>
/// The panel.
/// </summary>
public readonly VerticalPanel Panel = new VerticalPanel();
public readonly HorizontalPanel Panel = new HorizontalPanel();
/// <inheritdoc />
public override ContainerControl ContainerControl => Panel;

View File

@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Elements
{
/// <summary>
/// The horizontal panel element.
/// The vertical panel element.
/// </summary>
/// <seealso cref="FlaxEditor.CustomEditors.LayoutElement" />
public class HorizontalPanelElement : LayoutElementsContainer
public class VerticalPanelElement : LayoutElementsContainer
{
/// <summary>
/// The panel.
/// </summary>
public readonly HorizontalPanel Panel = new HorizontalPanel();
public readonly VerticalPanel Panel = new VerticalPanel();
/// <inheritdoc />
public override ContainerControl ContainerControl => Panel;

View File

@@ -112,7 +112,7 @@ namespace FlaxEditor.CustomEditors
OnAddElement(element);
return element;
}
/// <summary>
/// Adds new horizontal panel element.
/// </summary>
@@ -690,6 +690,17 @@ namespace FlaxEditor.CustomEditors
return element;
}
/// <summary>
/// Adds custom element to the layout.
/// </summary>
/// <param name="element">The element.</param>
public void AddElement(LayoutElement element)
{
if (element == null)
throw new ArgumentNullException();
OnAddElement(element);
}
/// <summary>
/// Called when element is added to the layout.
/// </summary>

View File

@@ -220,7 +220,7 @@ namespace FlaxEditor
GameProject = ProjectInfo.Load(Internal_GetProjectPath());
Icons = new EditorIcons();
Icons.GetIcons();
Icons.LoadIcons();
// Create common editor modules
RegisterModule(Options = new OptionsModule(this));
@@ -878,10 +878,12 @@ namespace FlaxEditor
/// Checks if can import asset with the given extension.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <param name="outputExtension">The output file extension (flax, json, etc.).</param>
/// <returns>True if can import files with given extension, otherwise false.</returns>
public static bool CanImport(string extension)
public static bool CanImport(string extension, out string outputExtension)
{
return Internal_CanImport(extension);
outputExtension = Internal_CanImport(extension);
return outputExtension != null;
}
/// <summary>
@@ -1183,6 +1185,8 @@ namespace FlaxEditor
var win = Windows.GameWin.Root;
if (win?.RootWindow is WindowRootControl root && root.Window && root.Window.IsFocused)
{
if (StateMachine.IsPlayMode && StateMachine.PlayingState.IsPaused)
return false;
return true;
}
}
@@ -1369,7 +1373,7 @@ namespace FlaxEditor
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool Internal_CanImport(string extension);
internal static extern string Internal_CanImport(string extension);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool Internal_CanExport(string path);

View File

@@ -16,102 +16,124 @@ namespace FlaxEditor
[HideInEditor]
public sealed class EditorIcons
{
public SpriteHandle FolderClosed12;
public SpriteHandle FolderOpened12;
// 12px
public SpriteHandle DragBar12;
public SpriteHandle ArrowDown12;
public SpriteHandle ArrowRight12;
public SpriteHandle Search12;
public SpriteHandle WindowDrag12;
public SpriteHandle CheckBoxIntermediate12;
public SpriteHandle ArrowRight12;
public SpriteHandle Settings12;
public SpriteHandle Cross12;
public SpriteHandle CheckBoxIntermediate12;
public SpriteHandle CheckBoxTick12;
public SpriteHandle StatusBarSizeGrip12;
public SpriteHandle ArrowDown12;
public SpriteHandle ArrowRightBorder16;
public SpriteHandle World16;
public SpriteHandle ScaleStep16;
public SpriteHandle RotateStep16;
public SpriteHandle Grid16;
public SpriteHandle Translate16;
public SpriteHandle Rotate16;
public SpriteHandle Scale16;
public SpriteHandle Link16;
public SpriteHandle Docs16;
public SpriteHandle Save32;
public SpriteHandle Undo32;
public SpriteHandle Redo32;
// 32px
public SpriteHandle Scalar32;
public SpriteHandle Translate32;
public SpriteHandle Rotate32;
public SpriteHandle Scale32;
public SpriteHandle Play32;
public SpriteHandle Pause32;
public SpriteHandle Step32;
public SpriteHandle Stop32;
public SpriteHandle PageScale32;
public SpriteHandle Bone32;
public SpriteHandle Docs32;
public SpriteHandle Import32;
public SpriteHandle AddDoc32;
public SpriteHandle RemoveDoc32;
public SpriteHandle BracketsSlash32;
public SpriteHandle Find32;
public SpriteHandle Reload32;
public SpriteHandle ArrowLeft32;
public SpriteHandle ArrowRight32;
public SpriteHandle ArrowDown32;
public SpriteHandle ArrowUp32;
public SpriteHandle Error32;
public SpriteHandle Warning32;
public SpriteHandle Info32;
public SpriteHandle UV32;
public SpriteHandle Image32;
public SpriteHandle Grid32;
public SpriteHandle Flax32;
public SpriteHandle RotateSnap32;
public SpriteHandle ScaleSnap32;
public SpriteHandle Globe32;
public SpriteHandle CamSpeed32;
public SpriteHandle Link32;
public SpriteHandle Next32;
public SpriteHandle Camera32;
public SpriteHandle Build32;
public SpriteHandle Add32;
public SpriteHandle Left32;
public SpriteHandle Right32;
public SpriteHandle Up32;
public SpriteHandle Down32;
public SpriteHandle FolderClosed32;
public SpriteHandle FolderOpen32;
public SpriteHandle Add48;
public SpriteHandle Paint48;
public SpriteHandle Foliage48;
public SpriteHandle Mountain48;
// Visject
public SpriteHandle VisjectBoxOpen32;
public SpriteHandle VisjectBoxClosed32;
public SpriteHandle VisjectArrowOpen32;
public SpriteHandle VisjectArrowClosed32;
public SpriteHandle Plugin64;
public SpriteHandle Document64;
public SpriteHandle CSharpScript64;
public SpriteHandle CppScript64;
// 64px
public SpriteHandle Flax64;
public SpriteHandle Save64;
public SpriteHandle Play64;
public SpriteHandle Stop64;
public SpriteHandle Pause64;
public SpriteHandle Skip64;
public SpriteHandle Info64;
public SpriteHandle Error64;
public SpriteHandle Warning64;
public SpriteHandle AddFile64;
public SpriteHandle DeleteFile64;
public SpriteHandle Import64;
public SpriteHandle Left64;
public SpriteHandle Right64;
public SpriteHandle Up64;
public SpriteHandle Down64;
public SpriteHandle Undo64;
public SpriteHandle Redo64;
public SpriteHandle Translate64;
public SpriteHandle Rotate64;
public SpriteHandle Scale64;
public SpriteHandle Refresh64;
public SpriteHandle Shift64;
public SpriteHandle Code64;
public SpriteHandle Folder64;
public SpriteHandle Scene64;
public SpriteHandle CodeScript64;
public SpriteHandle CenterView64;
public SpriteHandle Image64;
public SpriteHandle Camera64;
public SpriteHandle Docs64;
public SpriteHandle Search64;
public SpriteHandle Bone64;
public SpriteHandle Link64;
public SpriteHandle Build64;
public SpriteHandle Add64;
public SpriteHandle Logo128;
// 96px
public SpriteHandle Toolbox96;
public SpriteHandle Paint96;
public SpriteHandle Foliage96;
public SpriteHandle Terrain96;
public SpriteHandle VisjectBoxOpen;
public SpriteHandle VisjectBoxClose;
public SpriteHandle VisjectArrowOpen;
public SpriteHandle VisjectArrowClose;
// 128px
public SpriteHandle AndroidSettings128;
public SpriteHandle PlaystationSettings128;
public SpriteHandle InputSettings128;
public SpriteHandle PhysicsSettings128;
public SpriteHandle CSharpScript128;
public SpriteHandle Folder128;
public SpriteHandle WindowsIcon128;
public SpriteHandle LinuxIcon128;
public SpriteHandle UWPSettings128;
public SpriteHandle XBOXSettings128;
public SpriteHandle LayersTagsSettings128;
public SpriteHandle GraphicsSettings128;
public SpriteHandle CPPScript128;
public SpriteHandle Plugin128;
public SpriteHandle XBoxScarletIcon128;
public SpriteHandle AssetShadow128;
public SpriteHandle WindowsSettings128;
public SpriteHandle TimeSettings128;
public SpriteHandle GameSettings128;
public SpriteHandle VisualScript128;
public SpriteHandle Document128;
public SpriteHandle XBoxOne128;
public SpriteHandle UWPStore128;
public SpriteHandle ColorWheel128;
public SpriteHandle LinuxSettings128;
public SpriteHandle NavigationSettings128;
public SpriteHandle AudioSettings128;
public SpriteHandle BuildSettings128;
public SpriteHandle Scene128;
public SpriteHandle AndroidIcon128;
public SpriteHandle PS4Icon128;
public SpriteHandle FlaxLogo128;
public SpriteHandle AssetShadow;
public SpriteHandle ColorWheel;
public SpriteHandle Windows;
public SpriteHandle XboxOne;
public SpriteHandle WindowsStore;
public SpriteHandle Linux;
public SpriteHandle PS4;
public SpriteHandle XboxSeriesX;
public SpriteHandle Android;
internal void GetIcons()
internal void LoadIcons()
{
// Load asset
// Load & validate
var iconsAtlas = FlaxEngine.Content.LoadAsyncInternal<SpriteAtlas>(EditorAssets.IconsAtlas);
if (iconsAtlas == null)
{
Editor.LogError("Cannot load editor icons atlas.");
return;
}
if (iconsAtlas.WaitForLoaded())
if (iconsAtlas is null || iconsAtlas.WaitForLoaded())
{
Editor.LogError("Failed to load editor icons atlas.");
return;
@@ -122,11 +144,11 @@ namespace FlaxEditor
for (int i = 0; i < fields.Length; i++)
{
var field = fields[i];
var sprite = iconsAtlas.FindSprite(field.Name);
if (!sprite.IsValid)
{
Editor.LogWarning(string.Format("Failed to load sprite icon \'{0}\'.", field.Name));
}
Editor.LogWarning($"Failed to load sprite icon \'{field.Name}\'.");
field.SetValue(this, sprite);
}
}

View File

@@ -349,6 +349,8 @@ namespace FlaxEditor.GUI
/// </summary>
protected virtual void OnSelectedIndexChanged()
{
if (_tooltips != null && _tooltips.Length == _items.Count)
TooltipText = _selectedIndices.Count == 1 ? _tooltips[_selectedIndices[0]] : null;
SelectedIndexChanged?.Invoke(this);
}

View File

@@ -439,7 +439,7 @@ namespace FlaxEditor.GUI.ContextMenu
}
}
}
if (startIndex != -1)
if (startIndex > 0 && startIndex <= _panel.Children.Count)
{
// No more items found so start from the top if there are matching items
_panel.Children[startIndex - 1].Defocus();

View File

@@ -61,7 +61,7 @@ namespace FlaxEditor.GUI.Dialogs
public ColorSelector(float wheelSize = 64)
: base(0, 0, wheelSize, wheelSize)
{
_colorWheelSprite = Editor.Instance.Icons.ColorWheel;
_colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
}

View File

@@ -348,7 +348,7 @@ namespace FlaxEditor.GUI.Docking
// Cache data
IsMouseRightButtonDown = true;
if (MouseDownWindow != null)
_panel.SelectTab(MouseDownWindow);
_panel.SelectTab(MouseDownWindow, false);
}
else if (button == MouseButton.Middle)
{

View File

@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI
/// <summary>
/// The cached value from the UI.
/// </summary>
protected ulong _cachedValue;
protected long _cachedValue;
/// <summary>
/// True if has value cached, otherwise false.
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI
/// <summary>
/// The value.
/// </summary>
public ulong Value;
public long Value;
/// <summary>
/// Initializes a new instance of the <see cref="Entry"/> struct.
@@ -62,7 +62,7 @@ namespace FlaxEditor.GUI
/// <param name="name">The name.</param>
/// <param name="tooltip">The tooltip.</param>
/// <param name="value">The value.</param>
public Entry(string name, ulong value, string tooltip = null)
public Entry(string name, long value, string tooltip = null)
{
Name = name;
Tooltip = tooltip;
@@ -88,13 +88,13 @@ namespace FlaxEditor.GUI
public object EnumTypeValue
{
get => Enum.ToObject(_enumType, Value);
set => Value = Convert.ToUInt64(value);
set => Value = Convert.ToInt64(value);
}
/// <summary>
/// Gets or sets the value.
/// </summary>
public ulong Value
public long Value
{
get => _cachedValue;
set
@@ -209,7 +209,7 @@ namespace FlaxEditor.GUI
/// </summary>
protected void CacheValue()
{
ulong value = 0;
long value = 0;
if (IsFlags)
{
var selection = Selection;
@@ -276,7 +276,7 @@ namespace FlaxEditor.GUI
tooltip = tooltipAttr.Text;
}
entries.Add(new Entry(name, Convert.ToUInt64(field.GetRawConstantValue()), tooltip));
entries.Add(new Entry(name, Convert.ToInt64(field.GetRawConstantValue()), tooltip));
}
}
@@ -295,9 +295,9 @@ namespace FlaxEditor.GUI
}
// Calculate value that will be set after change
ulong valueAfter = 0;
long valueAfter = 0;
bool isSelected = _selectedIndices.Contains(index);
ulong selectedValue = entries[index].Value;
long selectedValue = entries[index].Value;
for (int i = 0; i < _selectedIndices.Count; i++)
{
int selectedIndex = _selectedIndices[i];

View File

@@ -23,10 +23,7 @@ namespace FlaxEditor.GUI.Input
value = Mathf.Clamp(value, _min, _max);
if (Math.Abs(_value - value) > Mathf.Epsilon)
{
// Set value
_value = value;
// Update
UpdateText();
OnValueChanged();
}
@@ -43,7 +40,6 @@ namespace FlaxEditor.GUI.Input
{
if (value > _max)
throw new ArgumentException();
_min = value;
Value = Value;
}
@@ -60,7 +56,6 @@ namespace FlaxEditor.GUI.Input
{
if (value < _min)
throw new ArgumentException();
_max = value;
Value = Value;
}
@@ -80,9 +75,19 @@ namespace FlaxEditor.GUI.Input
public FloatValueBox(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue, float slideSpeed = 1)
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
{
TryUseAutoSliderSpeed();
UpdateText();
}
private void TryUseAutoSliderSpeed()
{
var range = _max - _min;
if (Mathf.IsOne(_slideSpeed) && range > Mathf.Epsilon * 200.0f && range < 1000000.0f)
{
_slideSpeed = range * 0.01f;
}
}
/// <summary>
/// Sets the value limits.
/// </summary>
@@ -103,6 +108,7 @@ namespace FlaxEditor.GUI.Input
{
_min = limits.Min;
_max = Mathf.Max(_min, limits.Max);
TryUseAutoSliderSpeed();
Value = Value;
}
@@ -115,6 +121,7 @@ namespace FlaxEditor.GUI.Input
_min = limits.Min;
_max = Mathf.Max(_min, limits.Max);
_slideSpeed = limits.SliderSpeed;
TryUseAutoSliderSpeed();
Value = Value;
}

View File

@@ -184,7 +184,7 @@ namespace FlaxEditor.GUI.Input
var style = Style.Current;
// Draw sliding UI
Render2D.DrawSprite(style.Scale, SlideRect, style.Foreground);
Render2D.DrawSprite(style.Scalar, SlideRect, style.Foreground);
// Check if is sliding
if (_isSliding)

View File

@@ -82,14 +82,15 @@ namespace FlaxEditor.GUI
var icons = Editor.Instance.Icons;
var platforms = new[]
{
new PlatformData(PlatformType.Windows, icons.Windows, "Windows"),
new PlatformData(PlatformType.XboxOne, icons.XboxOne, "Xbox One"),
new PlatformData(PlatformType.UWP, icons.WindowsStore, "Windows Store"),
new PlatformData(PlatformType.Linux, icons.Linux, "Linux"),
new PlatformData(PlatformType.PS4, icons.PS4, "PlayStation 4"),
new PlatformData(PlatformType.XboxScarlett, icons.XboxSeriesX, "Xbox Scarlett"),
new PlatformData(PlatformType.Android, icons.Android, "Android"),
new PlatformData(PlatformType.Switch, icons.ColorWheel, "Switch"),
new PlatformData(PlatformType.Windows, icons.WindowsIcon128, "Windows"),
new PlatformData(PlatformType.XboxOne, icons.XBoxOne128, "Xbox One"),
new PlatformData(PlatformType.UWP, icons.UWPStore128, "Windows Store"),
new PlatformData(PlatformType.Linux, icons.LinuxIcon128, "Linux"),
new PlatformData(PlatformType.PS4, icons.PS4Icon128, "PlayStation 4"),
new PlatformData(PlatformType.XboxScarlett, icons.XBoxScarletIcon128, "Xbox Scarlett"),
new PlatformData(PlatformType.Android, icons.AndroidIcon128, "Android"),
new PlatformData(PlatformType.Switch, icons.ColorWheel128, "Switch"),
};
const float IconSize = 48.0f;

View File

@@ -79,7 +79,7 @@ namespace FlaxEditor.GUI
var type = allTypes[i];
if (_isValid(type))
{
var attributes = type.GetAttributes(false);
var attributes = type.GetAttributes(true);
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute) == null)
{
AddItem(new TypeItemView(type, attributes));

View File

@@ -63,7 +63,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
var isMouseOver = IsMouseOver;
var color = Gradient._data[Index].Value;
var icons = Editor.Instance.Icons;
var icon = icons.VisjectBoxClose;
var icon = icons.VisjectBoxClosed32;
Render2D.DrawSprite(icon, new Rectangle(0.0f, 0.0f, 10.0f, 10.0f), isMouseOver ? Color.Gray : Color.Black);
Render2D.DrawSprite(icon, new Rectangle(1.0f, 1.0f, 8.0f, 8.0f), color);

View File

@@ -26,7 +26,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
public override void Draw()
{
var style = Style.Current;
var icon = Editor.Instance.Icons.VisjectArrowClose;
var icon = Editor.Instance.Icons.VisjectArrowClosed32;
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y;
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);

View File

@@ -738,7 +738,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[0] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline start (Home)",
Brush = new SpriteBrush(icons.Step32),
Brush = new SpriteBrush(icons.Skip64),
Enabled = false,
Visible = false,
Rotation = 180.0f,
@@ -750,7 +750,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[1] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Seek back to the previous keyframe (Page Down)",
Brush = new SpriteBrush(icons.Next32),
Brush = new SpriteBrush(icons.Shift64),
Enabled = false,
Visible = false,
Rotation = 180.0f,
@@ -766,7 +766,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[2] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame back (Left Arrow)",
Brush = new SpriteBrush(icons.ArrowLeft32),
Brush = new SpriteBrush(icons.Left32),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -779,7 +779,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackStop = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Stop playback",
Brush = new SpriteBrush(icons.Stop32),
Brush = new SpriteBrush(icons.Stop64),
Visible = false,
Enabled = false,
Parent = playbackButtonsPanel
@@ -792,7 +792,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackPlay = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Play/pause playback (Space)",
Brush = new SpriteBrush(icons.Play32),
Brush = new SpriteBrush(icons.Play64),
Visible = false,
Tag = false, // Set to true if image is set to Pause, false if Play
Parent = playbackButtonsPanel
@@ -805,7 +805,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[3] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame forward (Right Arrow)",
Brush = new SpriteBrush(icons.ArrowRight32),
Brush = new SpriteBrush(icons.Right32),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -816,7 +816,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[4] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Seek to the next keyframe (Page Up)",
Brush = new SpriteBrush(icons.Next32),
Brush = new SpriteBrush(icons.Shift64),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -831,7 +831,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[5] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline end (End)",
Brush = new SpriteBrush(icons.Step32),
Brush = new SpriteBrush(icons.Skip64),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -1189,7 +1189,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
_playbackPlay.Brush = new SpriteBrush(icons.Play32);
_playbackPlay.Brush = new SpriteBrush(icons.Play64);
_playbackPlay.Tag = false;
}
if (_positionHandle != null)
@@ -1215,7 +1215,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
_playbackPlay.Brush = new SpriteBrush(icons.Pause32);
_playbackPlay.Brush = new SpriteBrush(icons.Pause64);
_playbackPlay.Tag = true;
}
if (_positionHandle != null)
@@ -1241,7 +1241,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
_playbackPlay.Brush = new SpriteBrush(icons.Play32);
_playbackPlay.Brush = new SpriteBrush(icons.Play64);
_playbackPlay.Tag = false;
}
if (_positionHandle != null)

View File

@@ -322,7 +322,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
Brush = new SpriteBrush(icons.ArrowRight32),
Brush = new SpriteBrush(icons.Right32),
Offsets = new Margin(-buttonSize - 2 + _muteCheckbox.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -335,7 +335,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(3),
Brush = new SpriteBrush(icons.Add48),
Brush = new SpriteBrush(icons.Add32),
Offsets = new Margin(-buttonSize - 2 + rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -348,7 +348,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
Brush = new SpriteBrush(icons.ArrowLeft32),
Brush = new SpriteBrush(icons.Left32),
Offsets = new Margin(-buttonSize - 2 + addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};

View File

@@ -695,7 +695,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
Brush = new SpriteBrush(icons.Camera32),
Brush = new SpriteBrush(icons.Camera64),
Offsets = new Margin(-buttonSize - 2 + _selectActor.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};

View File

@@ -128,7 +128,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
Brush = new SpriteBrush(icons.ArrowRight32),
Brush = new SpriteBrush(icons.Right64),
Offsets = new Margin(-buttonSize - 2 + uiLeft, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -138,9 +138,9 @@ namespace FlaxEditor.GUI.Timeline.Tracks
AutoFocus = true,
AnchorPreset = AnchorPresets.MiddleRight,
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Color = Style.Current.Foreground,
Margin = new Margin(3),
Brush = new SpriteBrush(icons.Add48),
Brush = new SpriteBrush(icons.Add64),
Offsets = new Margin(-buttonSize - 2 + _rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -150,9 +150,9 @@ namespace FlaxEditor.GUI.Timeline.Tracks
AutoFocus = true,
AnchorPreset = AnchorPresets.MiddleRight,
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Color = Style.Current.Foreground,
Margin = new Margin(1),
Brush = new SpriteBrush(icons.ArrowLeft32),
Brush = new SpriteBrush(icons.Left64),
Offsets = new Margin(-buttonSize - 2 + _addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};

View File

@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using FlaxEditor.Utilities;
using FlaxEngine;
using Newtonsoft.Json;
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor.History
{
@@ -114,6 +116,8 @@ namespace FlaxEditor.History
public object TargetInstance;
}
internal static JsonSerializerSettings JsonSettings;
// For objects that cannot be referenced in undo action like: FlaxEngine.Object or SceneGraphNode we store them in DataStorage,
// otherwise here:
private readonly object TargetInstance;
@@ -177,6 +181,24 @@ namespace FlaxEditor.History
};
}
/// <inheritdoc />
public override DataStorage Data
{
protected set
{
// Inject objects typename serialization to prevent data type mismatch when loading from saved state
var settings = JsonSettings;
if (settings == null)
{
settings = JsonSerializer.CreateDefaultSettings(false);
settings.TypeNameHandling = TypeNameHandling.All;
JsonSettings = settings;
}
_data = JsonConvert.SerializeObject(value, Formatting.Indented, settings);
//Editor.Log(_data);
}
}
/// <inheritdoc />
public override string ActionString { get; }

View File

@@ -96,10 +96,9 @@ struct InternalTextureOptions
to->Sprites.EnsureCapacity(count);
for (int32 i = 0; i < count; i++)
{
Sprite sprite;
Sprite& sprite = to->Sprites.AddOne();
sprite.Area = mono_array_get(from->SpriteAreas, Rectangle, i);
sprite.Name = MUtils::ToString(mono_array_get(from->SpriteNames, MonoString*, i));
to->Sprites.Add(sprite);
}
}
}
@@ -125,7 +124,7 @@ struct InternalTextureOptions
{
const auto domain = mono_domain_get();
int32 count = from->Sprites.Count();
auto rectClass = Scripting::FindClass("FlaxEngine.Rectangle");
auto rectClass = Rectangle::TypeInitializer.GetType().ManagedClass;
ASSERT(rectClass != nullptr);
to->SpriteAreas = mono_array_new(domain, rectClass->GetNative(), count);
to->SpriteNames = mono_array_new(domain, mono_get_string_class(), count);
@@ -521,13 +520,14 @@ public:
return AssetsImportingManager::Create(AssetsImportingManager::CreateVisualScriptTag, outputPath, &baseTypename);
}
static bool CanImport(MonoString* extensionObj)
static MonoString* CanImport(MonoString* extensionObj)
{
String extension;
MUtils::ToString(extensionObj, extension);
if (extension.Length() > 0 && extension[0] == '.')
extension.Remove(0, 1);
return AssetsImportingManager::GetImporter(extension) != nullptr;
const AssetImporter* importer = AssetsImportingManager::GetImporter(extension);
return importer ? MUtils::ToString(importer->ResultExtension) : nullptr;
}
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)

View File

@@ -911,6 +911,8 @@ namespace FlaxEditor.Modules
Proxy.Add(new ParticleSystemProxy());
Proxy.Add(new SceneAnimationProxy());
Proxy.Add(new CSharpScriptProxy());
Proxy.Add(new CppAssetProxy());
Proxy.Add(new CppStaticClassProxy());
Proxy.Add(new CppScriptProxy());
Proxy.Add(new SceneProxy());
Proxy.Add(new PrefabProxy());
@@ -923,32 +925,34 @@ namespace FlaxEditor.Modules
Proxy.Add(new SkeletonMaskProxy());
Proxy.Add(new GameplayGlobalsProxy());
Proxy.Add(new VisualScriptProxy());
Proxy.Add(new LocalizedStringTableProxy());
Proxy.Add(new FileProxy());
Proxy.Add(new SpawnableJsonAssetProxy<PhysicalMaterial>());
// Settings
Proxy.Add(new SettingsProxy(typeof(GameSettings)));
Proxy.Add(new SettingsProxy(typeof(TimeSettings)));
Proxy.Add(new SettingsProxy(typeof(LayersAndTagsSettings)));
Proxy.Add(new SettingsProxy(typeof(PhysicsSettings)));
Proxy.Add(new SettingsProxy(typeof(GraphicsSettings)));
Proxy.Add(new SettingsProxy(typeof(NavigationSettings)));
Proxy.Add(new SettingsProxy(typeof(BuildSettings)));
Proxy.Add(new SettingsProxy(typeof(InputSettings)));
Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings)));
Proxy.Add(new SettingsProxy(typeof(UWPPlatformSettings)));
Proxy.Add(new SettingsProxy(typeof(LinuxPlatformSettings)));
Proxy.Add(new SettingsProxy(typeof(GameSettings), Editor.Instance.Icons.GameSettings128));
Proxy.Add(new SettingsProxy(typeof(TimeSettings), Editor.Instance.Icons.TimeSettings128));
Proxy.Add(new SettingsProxy(typeof(LayersAndTagsSettings), Editor.Instance.Icons.LayersTagsSettings128));
Proxy.Add(new SettingsProxy(typeof(PhysicsSettings), Editor.Instance.Icons.PhysicsSettings128));
Proxy.Add(new SettingsProxy(typeof(GraphicsSettings), Editor.Instance.Icons.GraphicsSettings128));
Proxy.Add(new SettingsProxy(typeof(NavigationSettings), Editor.Instance.Icons.NavigationSettings128));
Proxy.Add(new SettingsProxy(typeof(LocalizationSettings), Editor.Instance.Icons.Document128));
Proxy.Add(new SettingsProxy(typeof(BuildSettings), Editor.Instance.Icons.BuildSettings128));
Proxy.Add(new SettingsProxy(typeof(InputSettings), Editor.Instance.Icons.InputSettings128));
Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings), Editor.Instance.Icons.WindowsSettings128));
Proxy.Add(new SettingsProxy(typeof(UWPPlatformSettings), Editor.Instance.Icons.UWPSettings128));
Proxy.Add(new SettingsProxy(typeof(LinuxPlatformSettings), Editor.Instance.Icons.LinuxSettings128));
var typePS4PlatformSettings = TypeUtils.GetManagedType(GameSettings.PS4PlatformSettingsTypename);
if (typePS4PlatformSettings != null)
Proxy.Add(new SettingsProxy(typePS4PlatformSettings));
Proxy.Add(new SettingsProxy(typePS4PlatformSettings, Editor.Instance.Icons.PlaystationSettings128));
var typeXboxScarlettPlatformSettings = TypeUtils.GetManagedType(GameSettings.XboxScarlettPlatformSettingsTypename);
if (typeXboxScarlettPlatformSettings != null)
Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings));
Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings)));
Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings, Editor.Instance.Icons.XBoxScarletIcon128));
Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings), Editor.Instance.Icons.AndroidSettings128));
var typeSwitchPlatformSettings = TypeUtils.GetManagedType(GameSettings.SwitchPlatformSettingsTypename);
if (typeSwitchPlatformSettings != null)
Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings));
Proxy.Add(new SettingsProxy(typeof(AudioSettings)));
Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings, Editor.Instance.Icons.Document128));
Proxy.Add(new SettingsProxy(typeof(AudioSettings), Editor.Instance.Icons.AudioSettings128));
// Last add generic json (won't override other json proxies)
Proxy.Add(new GenericJsonAssetProxy());

View File

@@ -118,6 +118,25 @@ namespace FlaxEditor.Modules
return false;
}
// Check proxy name restrictions
if (item is NewItem ni)
{
if (!ni.Proxy.IsFileNameValid(shortName))
{
hint = "Name does not follow " + ni.Proxy.Name + " name restrictions !";
return false;
}
}
else
{
var proxy = Editor.ContentDatabase.GetProxy(item);
if (proxy != null && !proxy.IsFileNameValid(shortName))
{
hint = "Name does not follow " + proxy.Name + " name restrictions !";
return false;
}
}
// Cache data
string sourcePath = item.Path;
string sourceFolder = System.IO.Path.GetDirectoryName(sourcePath);

View File

@@ -309,6 +309,7 @@ namespace FlaxEditor.Modules
{ "FlaxEditor.Content.Settings.InputSettings", "Settings" },
{ "FlaxEditor.Content.Settings.LayersAndTagsSettings", "Settings" },
{ "FlaxEditor.Content.Settings.NavigationSettings", "Settings" },
{ "FlaxEditor.Content.Settings.LocalizationSettings", "Settings" },
{ "FlaxEditor.Content.Settings.PhysicsSettings", "Settings" },
{ "FlaxEditor.Content.Settings.TimeSettings", "Settings" },
{ "FlaxEditor.Content.Settings.UWPPlatformSettings", "Settings" },

View File

@@ -193,12 +193,10 @@ namespace FlaxEditor.Modules
var extension = System.IO.Path.GetExtension(inputPath) ?? string.Empty;
// Check if given file extension is a binary asset (.flax files) and can be imported by the engine
bool isBinaryAsset = Editor.CanImport(extension);
string outputExtension;
if (isBinaryAsset)
bool isBuilt = Editor.CanImport(extension, out var outputExtension);
if (isBuilt)
{
// Flax it up!
outputExtension = ".flax";
outputExtension = '.' + outputExtension;
if (!targetLocation.CanHaveAssets)
{
@@ -234,7 +232,7 @@ namespace FlaxEditor.Modules
var shortName = System.IO.Path.GetFileNameWithoutExtension(inputPath);
var outputPath = System.IO.Path.Combine(targetLocation.Path, shortName + outputExtension);
Import(inputPath, outputPath, isBinaryAsset, skipSettingsDialog, settings);
Import(inputPath, outputPath, isBuilt, skipSettingsDialog, settings);
}
/// <summary>
@@ -243,10 +241,10 @@ namespace FlaxEditor.Modules
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="isBinaryAsset">True if output file is a binary asset.</param>
/// <param name="isInBuilt">True if use in-built importer (engine backend).</param>
/// <param name="skipSettingsDialog">True if skip any popup dialogs showing for import options adjusting. Can be used when importing files from code.</param>
/// <param name="settings">Import settings to override. Use null to skip this value.</param>
private void Import(string inputPath, string outputPath, bool isBinaryAsset, bool skipSettingsDialog = false, object settings = null)
private void Import(string inputPath, string outputPath, bool isInBuilt, bool skipSettingsDialog = false, object settings = null)
{
lock (_requests)
{
@@ -254,7 +252,7 @@ namespace FlaxEditor.Modules
{
InputPath = inputPath,
OutputPath = outputPath,
IsBinaryAsset = isBinaryAsset,
IsInBuilt = isInBuilt,
SkipSettingsDialog = skipSettingsDialog,
Settings = settings,
});

View File

@@ -190,7 +190,7 @@ namespace FlaxEditor.Modules
if (isDuringBreakpointHang)
{
play.Checked = false;
play.Icon = Editor.Icons.Stop32;
play.Icon = Editor.Icons.Stop64;
pause.Enabled = false;
pause.Checked = true;
pause.AutoCheck = false;
@@ -199,7 +199,7 @@ namespace FlaxEditor.Modules
else if (isPlayMode)
{
play.Checked = false;
play.Icon = Editor.Icons.Stop32;
play.Icon = Editor.Icons.Stop64;
pause.Enabled = true;
pause.Checked = Editor.StateMachine.PlayingState.IsPaused;
pause.AutoCheck = false;
@@ -208,7 +208,7 @@ namespace FlaxEditor.Modules
else
{
play.Checked = Editor.Simulation.IsPlayModeRequested;
play.Icon = Editor.Icons.Play32;
play.Icon = Editor.Icons.Play64;
pause.Enabled = canEnterPlayMode;
pause.AutoCheck = true;
step.Enabled = false;
@@ -501,20 +501,20 @@ namespace FlaxEditor.Modules
Parent = mainWindow,
};
_toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save32, Editor.SaveAll).LinkTooltip("Save all (Ctrl+S)");
_toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip("Save all (Ctrl+S)");
ToolStrip.AddSeparator();
_toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo32, Editor.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
_toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo32, Editor.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
_toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
ToolStrip.AddSeparator();
_toolStripTranslate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate (1)");
_toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate (2)");
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale (3)");
ToolStrip.AddSeparator();
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build32, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
ToolStrip.AddSeparator();
_toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play32, Editor.Simulation.RequestPlayOrStopPlay).LinkTooltip("Start/Stop game (F5)");
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause32, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game(F6)");
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Step32, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
_toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.RequestPlayOrStopPlay).LinkTooltip("Start/Stop game (F5)");
_toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game(F6)");
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
UpdateToolstrip();
}

View File

@@ -248,10 +248,11 @@ namespace FlaxEditor.Options
Cross = Editor.Icons.Cross12,
CheckBoxIntermediate = Editor.Icons.CheckBoxIntermediate12,
CheckBoxTick = Editor.Icons.CheckBoxTick12,
StatusBarSizeGrip = Editor.Icons.StatusBarSizeGrip12,
Translate = Editor.Icons.Translate16,
Rotate = Editor.Icons.Rotate16,
Scale = Editor.Icons.Scale16,
StatusBarSizeGrip = Editor.Icons.WindowDrag12,
Translate = Editor.Icons.Translate32,
Rotate = Editor.Icons.Rotate32,
Scale = Editor.Icons.Scale32,
Scalar = Editor.Icons.Scalar32,
SharedTooltip = new Tooltip()
};

View File

@@ -194,7 +194,7 @@ namespace FlaxEditor.SceneGraph
{
get
{
var scene = _actor.Scene;
var scene = _actor ? _actor.Scene : null;
return scene != null ? SceneGraphFactory.FindNode(scene.ID) as SceneNode : null;
}
}
@@ -235,7 +235,6 @@ namespace FlaxEditor.SceneGraph
{
if (!(value is ActorNode))
throw new InvalidOperationException("ActorNode can have only ActorNode as a parent node.");
base.ParentNode = value;
}
}
@@ -289,6 +288,13 @@ namespace FlaxEditor.SceneGraph
{
}
/// <summary>
/// Action called after pasting actor in editor.
/// </summary>
public virtual void PostPaste()
{
}
/// <inheritdoc />
protected override void OnParentChanged()
{
@@ -299,6 +305,7 @@ namespace FlaxEditor.SceneGraph
// (eg. we build new node for spawned actor and link it to the game)
if (_treeNode.Parent != null && !_treeNode.Parent.IsLayoutLocked)
{
_treeNode.IndexInParent = _actor.OrderInParent;
_treeNode.Parent.SortChildren();
// Update UI

View File

@@ -25,5 +25,20 @@ namespace FlaxEditor.SceneGraph.Actors
if (Actor is UIControl uiControl)
DebugDraw.DrawWireBox(uiControl.Bounds, Color.BlueViolet);
}
/// <inheritdoc />
public override void PostPaste()
{
base.PostPaste();
var control = ((UIControl)Actor).Control;
if (control != null)
{
if (control.Parent != null)
control.Parent.PerformLayout();
else
control.PerformLayout();
}
}
}
}

View File

@@ -86,6 +86,10 @@ namespace FlaxEditor.SceneGraph.GUI
}
parent.SortChildren();
}
else if (Actor)
{
_orderInParent = Actor.OrderInParent;
}
}
internal void OnNameChanged()
@@ -537,7 +541,7 @@ namespace FlaxEditor.SceneGraph.GUI
var customAction = targetActor.HasPrefabLink ? new ReparentAction(targetActor) : null;
using (new UndoBlock(ActorNode.Root.Undo, targetActor, "Change actor parent", customAction))
{
targetActor.SetParent(newParent, worldPositionLock);
targetActor.SetParent(newParent, worldPositionLock, true);
targetActor.OrderInParent = newOrder;
}
}
@@ -550,7 +554,7 @@ namespace FlaxEditor.SceneGraph.GUI
for (int i = 0; i < targetActors.Count; i++)
{
var targetActor = targetActors[i];
targetActor.SetParent(newParent, worldPositionLock);
targetActor.SetParent(newParent, worldPositionLock, true);
targetActor.OrderInParent = newOrder;
}
}

View File

@@ -112,18 +112,9 @@ namespace FlaxEditor.SceneGraph
{
if (parentNode != value)
{
if (parentNode != null)
{
parentNode.ChildNodes.Remove(this);
}
parentNode?.ChildNodes.Remove(this);
parentNode = value;
if (parentNode != null)
{
parentNode.ChildNodes.Add(this);
}
parentNode?.ChildNodes.Add(this);
OnParentChanged();
}
}
@@ -374,6 +365,7 @@ namespace FlaxEditor.SceneGraph
/// <summary>
/// Gets or sets the node state.
/// </summary>
[NoSerialize]
public virtual StateData State
{
get => throw new NotImplementedException();

View File

@@ -9,6 +9,7 @@
#include "Engine/Core/Types/StringBuilder.h"
#include "Engine/Debug/Exceptions/FileNotFoundException.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Platform/FileSystemWatcher.h"
#include "Engine/Threading/ThreadPool.h"

View File

@@ -576,7 +576,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < _parameters.Length; i++)
{
writer.Write(_parameters[i].Name); // Parameter name
Utilities.Utils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
Utilities.VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
}
SetValue(2, stream.ToArray());
}
@@ -594,7 +594,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < parametersCount; i++)
{
var parameterName = reader.ReadString(); // Parameter name
var boxType = Utilities.Utils.ReadVariantType(reader); // Box type
var boxType = Utilities.VariantUtils.ReadVariantType(reader); // Box type
MakeBox(i + 1, parameterName, boxType);
}
}
@@ -778,14 +778,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static
signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name
param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out
}
}
@@ -799,14 +799,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static
signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray<SignatureParamInfo>();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
param.Name = reader.ReadString(); // Parameter name
param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out
}
}
@@ -823,13 +823,13 @@ namespace FlaxEditor.Surface.Archetypes
{
writer.Write((byte)4); // Version
writer.Write(methodInfo.IsStatic); // Is Static
Utilities.Utils.WriteVariantType(writer, methodInfo.ValueType); // Return type
Utilities.VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
writer.Write(parameters.Length); // Parameters count
for (int i = 0; i < parameters.Length; i++)
{
ref var param = ref parameters[i];
Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name
Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out
}
return stream.ToArray();
@@ -1434,14 +1434,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_signature.IsVirtual)
flags |= Flags.Virtual;
writer.Write((byte)flags); // Flags
Utilities.Utils.WriteVariantType(writer, _signature.ReturnType); // Return Type
Utilities.VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
var parametersCount = _signature.Parameters?.Length ?? 0;
writer.Write(parametersCount); // Parameters count
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref _signature.Parameters[i];
Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name
Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)0); // Is parameter out
writer.Write((byte)0); // Has default value
}
@@ -1470,13 +1470,13 @@ namespace FlaxEditor.Surface.Archetypes
var flags = (Flags)reader.ReadByte(); // Flags
_signature.IsStatic = (flags & Flags.Static) == Flags.Static;
_signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual;
_signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return Type
_signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return Type
var parametersCount = reader.ReadInt32(); // Parameters count
_signature.Parameters = new Parameter[parametersCount];
for (int i = 0; i < parametersCount; i++)
{
var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name
var paramType = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
var paramType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
var isOut = reader.ReadByte() != 0; // Is parameter out
var hasDefaultValue = reader.ReadByte() != 0; // Has default value
_signature.Parameters[i] = new Parameter
@@ -1993,7 +1993,7 @@ namespace FlaxEditor.Surface.Archetypes
}
else if (_isBind)
{
_helperButton.Brush = new SpriteBrush(Editor.Instance.Icons.Add48);
_helperButton.Brush = new SpriteBrush(Editor.Instance.Icons.Add64);
_helperButton.Color = Color.Red;
_helperButton.TooltipText = "Add new handler function and bind it to this event";
_helperButton.Enabled = _signature != null;

View File

@@ -171,7 +171,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type
Utilities.Utils.WriteVariantType(writer, fields[i].ValueType); // Field type
Utilities.VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
}
Values[1] = stream.ToArray();
}
@@ -188,7 +188,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name
var fieldType = Utilities.Utils.ReadVariantType(reader); // Field type
var fieldType = Utilities.VariantUtils.ReadVariantType(reader); // Field type
MakeBox(i + 1, fieldName, new ScriptType(fieldType));
}
}

View File

@@ -104,7 +104,7 @@ namespace FlaxEditor.Surface.Archetypes
color *= 1.3f;
color.A = 1.0f;
var icons = Editor.Instance.Icons;
var icon = isSelected ? icons.VisjectArrowClose : icons.VisjectArrowOpen;
var icon = isSelected ? icons.VisjectArrowClosed32 : icons.VisjectArrowOpen32;
Render2D.PushTransform(ref arrowTransform);
Render2D.DrawSprite(icon, arrowRect, color);

View File

@@ -32,7 +32,7 @@ namespace FlaxEditor.Surface.Elements
Width = archetype.Size.X;
ParentNode = parentNode;
Archetype = archetype;
Value = (ulong)(int)ParentNode.Values[Archetype.ValueIndex];
Value = (int)ParentNode.Values[Archetype.ValueIndex];
}
/// <inheritdoc />

View File

@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Input;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using Newtonsoft.Json;
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor.Surface.Elements
{
@@ -981,6 +983,121 @@ namespace FlaxEditor.Surface.Elements
}
}
/// <inheritdoc />
public override bool OnMouseUp(Vector2 location, MouseButton button)
{
if (button == MouseButton.Right && Archetype.ValueIndex != -1)
{
var menu = new FlaxEditor.GUI.ContextMenu.ContextMenu();
menu.AddButton("Copy value", OnCopyValue);
var paste = menu.AddButton("Paste value", OnPasteValue);
try
{
GetClipboardValue(out _, false);
}
catch
{
paste.Enabled = false;
}
menu.Show(this, location);
return true;
}
return base.OnMouseUp(location, button);
}
private bool GetClipboardValue(out object result, bool deserialize)
{
result = null;
var text = Clipboard.Text;
if (string.IsNullOrEmpty(text))
return false;
object obj;
var type = CurrentType;
if (new ScriptType(typeof(FlaxEngine.Object)).IsAssignableFrom(type))
{
// Object reference
if (text.Length != 32)
return false;
JsonSerializer.ParseID(text, out var id);
obj = FlaxEngine.Object.Find<FlaxEngine.Object>(ref id);
}
else
{
// Default
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(type), JsonSerializer.Settings);
}
if (obj == null || type.IsInstanceOfType(obj))
{
result = obj;
return true;
}
return false;
}
private void OnCopyValue()
{
var value = ParentNode.Values[Archetype.ValueIndex];
try
{
string text;
if (value == null)
{
// Missing value
var type = CurrentType;
if (type.Type == typeof(bool))
text = "false";
else if (type.Type == typeof(byte) || type.Type == typeof(sbyte) || type.Type == typeof(char) || type.Type == typeof(short) || type.Type == typeof(ushort) || type.Type == typeof(int) || type.Type == typeof(uint) || type.Type == typeof(long) || type.Type == typeof(ulong))
text = "0";
else if (type.Type == typeof(float) || type.Type == typeof(double))
text = "0.0";
else if (type.Type == typeof(Vector2) || type.Type == typeof(Vector3) || type.Type == typeof(Vector4) || type.Type == typeof(Color))
text = JsonSerializer.Serialize(TypeUtils.GetDefaultValue(type));
else if (type.Type == typeof(string))
text = "";
else
text = "null";
}
else if (value is FlaxEngine.Object asObject)
{
// Object reference
text = JsonSerializer.GetStringID(asObject);
}
else
{
// Default
text = JsonSerializer.Serialize(value);
}
Clipboard.Text = text;
}
catch (Exception ex)
{
Editor.LogWarning(ex);
Editor.LogError("Cannot copy property. See log for more info.");
}
}
private void OnPasteValue()
{
try
{
if (GetClipboardValue(out var value, true))
{
ParentNode.SetValue(Archetype.ValueIndex, value);
}
}
catch (Exception ex)
{
Editor.LogWarning(ex);
Editor.LogError("Cannot paste property value. See log for more info.");
}
}
/// <summary>
/// Creates the default value editor control.
/// </summary>

View File

@@ -224,10 +224,10 @@ namespace FlaxEditor.Surface
},
Icons =
{
BoxOpen = editor.Icons.VisjectBoxOpen,
BoxClose = editor.Icons.VisjectBoxClose,
ArrowOpen = editor.Icons.VisjectArrowOpen,
ArrowClose = editor.Icons.VisjectArrowClose,
BoxOpen = editor.Icons.VisjectBoxOpen32,
BoxClose = editor.Icons.VisjectBoxClosed32,
ArrowOpen = editor.Icons.VisjectArrowOpen32,
ArrowClose = editor.Icons.VisjectArrowClosed32,
},
Background = editor.UI.VisjectSurfaceBackground,
};

View File

@@ -759,12 +759,12 @@ namespace FlaxEditor.Surface
_propertiesEditor.Modified += OnPropertyEdited;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.PageScale32, ShowWholeGraph).LinkTooltip("Show whole graph");
_toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);

View File

@@ -140,22 +140,27 @@ namespace FlaxEditor.Actions
for (int i = 0; i < nodeParents.Count; i++)
{
// Fix name collisions (only for parents)
var node = nodeParents[i];
var parent = node.Actor?.Parent;
if (parent != null)
{
// Fix name collisions
string name = node.Name;
Actor[] children = parent.Children;
if (children.Any(x => x.Name == name))
{
// Generate new name
node.Actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
}
}
Editor.Instance.Scene.MarkSceneEdited(node.ParentScene);
}
for (int i = 0; i < nodeParents.Count; i++)
{
var node = nodeParents[i];
node.PostPaste();
}
}
/// <summary>

View File

@@ -4,7 +4,6 @@ using System;
using FlaxEditor.SceneGraph;
using FlaxEngine;
using Newtonsoft.Json;
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor
{
@@ -28,7 +27,6 @@ namespace FlaxEditor
var id = Guid.Parse((string)reader.Value);
return SceneGraphFactory.FindNode(id);
}
return null;
}
@@ -56,19 +54,11 @@ namespace FlaxEditor
/// <summary>
/// Gets or sets the serialized undo data.
/// </summary>
/// <value>
/// The data.
/// </value>
[NoSerialize]
public TData Data
public virtual TData Data
{
get => JsonConvert.DeserializeObject<TData>(_data, JsonSerializer.Settings);
protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, JsonSerializer.Settings);
/*protected set
{
_data = JsonConvert.SerializeObject(value, Formatting.Indented, JsonSerializer.Settings);
Debug.Info(_data);
}*/
get => JsonConvert.DeserializeObject<TData>(_data, FlaxEngine.Json.JsonSerializer.Settings);
protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, FlaxEngine.Json.JsonSerializer.Settings);
}
/// <inheritdoc />

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "EditorUtilities.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Core/Log.h"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -443,7 +443,7 @@ namespace FlaxEditor.Viewport
// Camera speed widget
var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var camSpeedCM = new ContextMenu();
var camSpeedButton = new ViewportWidgetButton(_movementSpeed.ToString(), Editor.Instance.Icons.ArrowRightBorder16, camSpeedCM)
var camSpeedButton = new ViewportWidgetButton(_movementSpeed.ToString(), Editor.Instance.Icons.CamSpeed32, camSpeedCM)
{
Tag = this,
TooltipText = "Camera speed scale"
@@ -484,7 +484,7 @@ namespace FlaxEditor.Viewport
// View Flags
{
var viewFlags = ViewWidgetButtonMenu.AddChildMenu("View Flags").ContextMenu;
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate16;
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddSeparator();
for (int i = 0; i < EditorViewportViewFlagsValues.Length; i++)
{
@@ -974,7 +974,8 @@ namespace FlaxEditor.Viewport
// Get input buttons and keys (skip if viewport has no focus or mouse is over a child control)
bool useMouse = Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height);
_prevInput = _input;
if (ContainsFocus && GetChildAt(_viewMousePos, c => c.Visible) == null)
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl));
if (ContainsFocus && hit == null)
_input.Gather(win.Window, useMouse);
else
_input.Clear();

View File

@@ -165,6 +165,11 @@ namespace FlaxEditor.Viewport
/// </summary>
public bool DrawDebugDraw = true;
/// <summary>
/// Gets the debug draw data for the viewport.
/// </summary>
public ViewportDebugDrawData DebugDrawData => _debugDrawData;
/// <summary>
/// Gets or sets a value indicating whether show navigation mesh.
/// </summary>
@@ -219,7 +224,7 @@ namespace FlaxEditor.Viewport
// Transform space widget
var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.World16, null, true)
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
TooltipText = "Gizmo transform space (world or local)",
@@ -230,7 +235,7 @@ namespace FlaxEditor.Viewport
// Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleStep16, null, true)
var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleSnap32, null, true)
{
Checked = TransformGizmo.ScaleSnapEnabled,
TooltipText = "Enable scale snapping",
@@ -257,7 +262,7 @@ namespace FlaxEditor.Viewport
// Rotation snapping widget
var rotateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableRotateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.RotateStep16, null, true)
var enableRotateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.RotateSnap32, null, true)
{
Checked = TransformGizmo.RotationSnapEnabled,
TooltipText = "Enable rotation snapping",
@@ -284,7 +289,7 @@ namespace FlaxEditor.Viewport
// Translation snapping widget
var translateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.Grid16, null, true)
var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.Grid32, null, true)
{
Checked = TransformGizmo.TranslationSnapEnable,
TooltipText = "Enable position snapping",
@@ -311,7 +316,7 @@ namespace FlaxEditor.Viewport
// Gizmo mode widget
var gizmoMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate16, null, true)
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
TooltipText = "Translate gizmo mode",
@@ -319,14 +324,14 @@ namespace FlaxEditor.Viewport
Parent = gizmoMode
};
_gizmoModeTranslate.Toggled += OnGizmoModeToggle;
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate16, null, true)
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
TooltipText = "Rotate gizmo mode",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
_gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale16, null, true)
_gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
TooltipText = "Scale gizmo mode",
@@ -389,10 +394,11 @@ namespace FlaxEditor.Viewport
return;
// Create actor
var parent = Level.GetScene(0);
var actor = new Camera
{
StaticFlags = StaticFlags.None,
Name = "Camera",
Name = StringUtils.IncrementNameNumber("Camera", x => parent.GetChild(x) == null),
Transform = ViewTransform,
NearPlane = NearPlane,
FarPlane = FarPlane,
@@ -402,7 +408,7 @@ namespace FlaxEditor.Viewport
};
// Spawn
Editor.Instance.SceneEditing.Spawn(actor);
Editor.Instance.SceneEditing.Spawn(actor, parent);
}
private void OnBegin(RenderTask task, GPUContext context)
@@ -877,6 +883,8 @@ namespace FlaxEditor.Viewport
private void Spawn(Actor actor, ref Vector3 hitLocation)
{
actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation);
var parent = actor.Parent ?? Level.GetScene(0);
actor.Name = StringUtils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
Editor.Instance.SceneEditing.Spawn(actor);
Focus();
}

View File

@@ -118,7 +118,7 @@ namespace FlaxEditor.Viewport
// Transform space widget
var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.World16, null, true)
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
TooltipText = "Gizmo transform space (world or local)",
@@ -129,7 +129,7 @@ namespace FlaxEditor.Viewport
// Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableScaleSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.ScaleStep16, null, true)
var enableScaleSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.ScaleSnap32, null, true)
{
Checked = TransformGizmo.ScaleSnapEnabled,
TooltipText = "Enable scale snapping",
@@ -156,7 +156,7 @@ namespace FlaxEditor.Viewport
// Rotation snapping widget
var rotateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableRotateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.RotateStep16, null, true)
var enableRotateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.RotateSnap32, null, true)
{
Checked = TransformGizmo.RotationSnapEnabled,
TooltipText = "Enable rotation snapping",
@@ -183,7 +183,7 @@ namespace FlaxEditor.Viewport
// Translation snapping widget
var translateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Grid16, null, true)
var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Grid32, null, true)
{
Checked = TransformGizmo.TranslationSnapEnable,
TooltipText = "Enable position snapping",
@@ -210,7 +210,7 @@ namespace FlaxEditor.Viewport
// Gizmo mode widget
var gizmoMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate16, null, true)
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
TooltipText = "Translate gizmo mode",
@@ -218,14 +218,14 @@ namespace FlaxEditor.Viewport
Parent = gizmoMode
};
_gizmoModeTranslate.Toggled += OnGizmoModeToggle;
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate16, null, true)
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
TooltipText = "Rotate gizmo mode",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
_gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale16, null, true)
_gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
TooltipText = "Scale gizmo mode",

View File

@@ -34,7 +34,7 @@ namespace FlaxEditor.Windows
{
Image icon = new Image(4, 4, 80, 80)
{
Brush = new SpriteBrush(Editor.Instance.Icons.Logo128),
Brush = new SpriteBrush(Editor.Instance.Icons.FlaxLogo128),
Parent = this
};
var nameLabel = new Label(icon.Right + 10, icon.Top, 200, 34)
@@ -131,6 +131,7 @@ namespace FlaxEditor.Windows
"LZ4 Library - Copyright (c) Yann Collet. All rights reserved.",
"fmt - www.fmtlib.net",
"minimp3 - www.github.com/lieff/minimp3",
"Tracy Profiler - www.github.com/wolfpld/tracy",
"Ogg and Vorbis - Xiph.org Foundation",
"OpenAL Soft - www.github.com/kcat/openal-soft",
"OpenFBX - www.github.com/nem0/OpenFBX",

Some files were not shown because too many files have changed in this diff Show More