diff --git a/Source/Editor/Modules/ContentEditingModule.cs b/Source/Editor/Modules/ContentEditingModule.cs index 3db27af40..a6d8132f0 100644 --- a/Source/Editor/Modules/ContentEditingModule.cs +++ b/Source/Editor/Modules/ContentEditingModule.cs @@ -90,6 +90,12 @@ namespace FlaxEditor.Modules hint = "Too long name."; return false; } + + if (item.IsFolder && shortName.EndsWith(".")) + { + hint = "Name cannot end with '.'"; + return false; + } // Find invalid characters if (Utilities.Utils.HasInvalidPathChar(shortName)) @@ -120,7 +126,7 @@ namespace FlaxEditor.Modules // Cache data string sourcePath = item.Path; string sourceFolder = System.IO.Path.GetDirectoryName(sourcePath); - string extension = System.IO.Path.GetExtension(sourcePath); + string extension = item.IsFolder ? "" : System.IO.Path.GetExtension(sourcePath); string destinationPath = StringUtils.CombinePaths(sourceFolder, shortName + extension); if (item.IsFolder) diff --git a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp index e28d1e381..05608d71e 100644 --- a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp +++ b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp @@ -24,7 +24,8 @@ namespace String version; RiderInstallation(const String& path_, const String& version_) - : path(path_), version(version_) + : path(path_) + , version(version_) { } }; @@ -44,6 +45,10 @@ namespace if (document.HasParseError()) return; + // Check if this is actually rider and not another jetbrains product + if (document.FindMember("name")->value != "JetBrains Rider") + return; + // Find version auto versionMember = document.FindMember("version"); if (versionMember == document.MemberEnd()) @@ -141,14 +146,14 @@ bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i int32 version2[3] = { 0 }; StringUtils::Parse(values1[0].Get(), &version1[0]); StringUtils::Parse(values1[1].Get(), &version1[1]); - - if(values1.Count() > 2) + + if (values1.Count() > 2) StringUtils::Parse(values1[2].Get(), &version1[2]); - + StringUtils::Parse(values2[0].Get(), &version2[0]); StringUtils::Parse(values2[1].Get(), &version2[1]); - - if(values2.Count() > 2) + + if (values2.Count() > 2) StringUtils::Parse(values2[2].Get(), &version2[2]); // Compare by MAJOR.MINOR.BUILD @@ -174,7 +179,7 @@ void RiderCodeEditor::FindEditors(Array* output) String localAppDataPath; FileSystem::GetSpecialFolderPath(SpecialFolder::LocalAppData, localAppDataPath); - + #if PLATFORM_WINDOWS // Lookup from all known registry locations SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\Rider for Unreal Engine")); @@ -187,6 +192,7 @@ void RiderCodeEditor::FindEditors(Array* output) SearchRegistry(&installations, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider")); // Versions installed via JetBrains Toolbox + FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("Programs")); FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-0\\")); FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-1\\")); // Beta versions #endif @@ -201,6 +207,7 @@ void RiderCodeEditor::FindEditors(Array* output) FileSystem::GetChildDirectories(subDirectories, TEXT("/opt/")); // Versions installed via JetBrains Toolbox + SearchDirectory(&installations, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/rider/")); FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-0")); FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-1")); // Beta versions @@ -210,7 +217,24 @@ void RiderCodeEditor::FindEditors(Array* output) TEXT("flatpak run com.jetbrains.Rider")); #endif - for (auto directory : subDirectories) +#if PLATFORM_MAC + String applicationSupportFolder; + FileSystem::GetSpecialFolderPath(SpecialFolder::ProgramData, applicationSupportFolder); + + Array subMacDirectories; + FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-0/")); + FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-1/")); + for (const String& directory : subMacDirectories) + { + String riderAppDirectory = directory / TEXT("Rider.app/Contents/Resources"); + SearchDirectory(&installations, riderAppDirectory); + } + + // Check the local installer version + SearchDirectory(&installations, TEXT("/Applications/Rider.app/Contents/Resources")); +#endif + + for (const String& directory : subDirectories) SearchDirectory(&installations, directory); // Sort found installations by version number diff --git a/Source/Editor/Surface/Archetypes/Math.cs b/Source/Editor/Surface/Archetypes/Math.cs index 1b8f62e62..fe2f1e044 100644 --- a/Source/Editor/Surface/Archetypes/Math.cs +++ b/Source/Editor/Surface/Archetypes/Math.cs @@ -126,7 +126,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Clamp", Description = "Clamps value to the specified range", Flags = NodeFlags.AllGraphs, - Size = new Float2(110, 60), + Size = new Float2(140, 60), ConnectionsHints = ConnectionsHint.Numeric, IndependentBoxes = new[] { 0 }, DependentBoxes = new[] { 1, 2, 3 }, diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index 91e4ec1b5..2628735eb 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -520,7 +520,7 @@ namespace FlaxEditor.Windows } // Cache data - string extension = Path.GetExtension(item.Path); + string extension = item.IsFolder ? "" : Path.GetExtension(item.Path); var newPath = StringUtils.CombinePaths(item.ParentFolder.Path, newShortName + extension); // Check if was renaming mock element diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 74d6e6bad..a74299670 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -32,6 +32,7 @@ namespace FlaxEngine.Interop public static class NativeToManaged { public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target; + public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero; public static void Free(IntPtr unmanaged) { @@ -44,6 +45,7 @@ namespace FlaxEngine.Interop #endif public static class ManagedToNative { + public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target; public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero; public static void Free(IntPtr unmanaged) @@ -147,29 +149,16 @@ namespace FlaxEngine.Interop #if FLAX_EDITOR [HideInEditor] #endif - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))] - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))] - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))] - [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller))] + [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller))] public static class ObjectMarshaller { -#if FLAX_EDITOR - [HideInEditor] -#endif - public static class NativeToManaged - { - public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target) : null; - } - -#if FLAX_EDITOR - [HideInEditor] -#endif - public static class ManagedToNative - { - public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero; - } + public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target) : null; + public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero; } #if FLAX_EDITOR @@ -342,6 +331,7 @@ namespace FlaxEngine.Interop public static class NativeToManaged { public static Dictionary ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller.ToManaged(unmanaged); + public static IntPtr ConvertToUnmanaged(Dictionary managed) => DictionaryMarshaller.ToNative(managed, GCHandleType.Weak); public static void Free(IntPtr unmanaged) => DictionaryMarshaller.Free(unmanaged); } @@ -350,8 +340,8 @@ namespace FlaxEngine.Interop #endif public static class ManagedToNative { + public static Dictionary ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller.ToManaged(unmanaged); public static IntPtr ConvertToUnmanaged(Dictionary managed) => DictionaryMarshaller.ToNative(managed, GCHandleType.Weak); - public static void Free(IntPtr unmanaged) { //DictionaryMarshaller.Free(unmanaged); // No need to free weak handles @@ -425,6 +415,28 @@ namespace FlaxEngine.Interop return new T[numElements]; } + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) + { + if (managed is null) + { + numElements = 0; + return null; + } + numElements = managed.Length; + (ManagedHandle managedArrayHandle, _) = ManagedArray.AllocatePooledArray(managed.Length); + return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArrayHandle); + } + + public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; + + public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged) + { + if (unmanaged == null) + return Span.Empty; + ManagedArray managedArray = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); + return managedArray.ToSpan(); + } + public static Span GetManagedValuesDestination(T[] managed) => managed; public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) @@ -591,6 +603,7 @@ namespace FlaxEngine.Interop public static class NativeToManaged { public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged); + public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak); public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged); } @@ -599,11 +612,8 @@ namespace FlaxEngine.Interop #endif public static class ManagedToNative { - public static unsafe IntPtr ConvertToUnmanaged(string managed) - { - return managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak); - } - + public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged); + public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak); public static void Free(IntPtr unmanaged) { //ManagedString.Free(unmanaged); // No need to free weak handles diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 2c1bab744..e96839546 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -184,7 +184,7 @@ namespace FlaxEngine.Interop { string moduleName = Marshal.PtrToStringAnsi(moduleNamePtr); string modulePath = Marshal.PtrToStringAnsi(modulePathPtr); - nativeLibraryPaths[moduleName] = modulePath; + libraryPaths[moduleName] = modulePath; } [UnmanagedCallersOnly] @@ -909,7 +909,7 @@ namespace FlaxEngine.Interop loadedNativeLibraries.Remove(nativeLibraryName); } if (nativeLibraryName != null) - nativeLibraryPaths.Remove(nativeLibraryName); + libraryPaths.Remove(nativeLibraryName); } [UnmanagedCallersOnly] diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index dd6087b98..8a8d543f1 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -50,7 +50,7 @@ namespace FlaxEngine.Interop private static Dictionary _typeSizeCache = new(); private static Dictionary loadedNativeLibraries = new(); - internal static Dictionary nativeLibraryPaths = new(); + internal static Dictionary libraryPaths = new(); private static Dictionary assemblyOwnedNativeLibraries = new(); internal static AssemblyLoadContext scriptingAssemblyLoadContext; @@ -59,7 +59,7 @@ namespace FlaxEngine.Interop { if (!loadedNativeLibraries.TryGetValue(libraryName, out IntPtr nativeLibrary)) { - if (!nativeLibraryPaths.TryGetValue(libraryName, out var nativeLibraryPath)) + if (!libraryPaths.TryGetValue(libraryName, out var nativeLibraryPath)) nativeLibraryPath = libraryName; nativeLibrary = NativeLibrary.Load(nativeLibraryPath, assembly, dllImportSearchPath); @@ -101,9 +101,9 @@ namespace FlaxEngine.Interop private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) { // FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored - foreach (string nativeLibraryPath in nativeLibraryPaths.Values) + foreach (string libraryPath in libraryPaths.Values) { - string editorTargetPath = Path.GetDirectoryName(nativeLibraryPath); + string editorTargetPath = Path.GetDirectoryName(libraryPath); var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll"); if (File.Exists(assemblyPath)) diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index 46b978e1d..8cba5e1dc 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -462,6 +462,9 @@ int32 MacPlatform::CreateProcess(CreateProcessSettings& settings) } } + // Sanatize the string if the exePath has spaces with properly espcaped spaces for popen + exePath.Replace(TEXT(" "), TEXT("\\ ")); + const String cmdLine = exePath + TEXT(" ") + settings.Arguments; const StringAsANSI<> cmdLineAnsi(*cmdLine, cmdLine.Length()); FILE* pipe = popen(cmdLineAnsi.Get(), "r"); diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 6ffdb14a9..8f1bb27d0 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -1009,12 +1009,36 @@ void ManagedBinaryModule::InitType(MClass* mclass) } if (baseType.Module == this) InitType(baseClass); // Ensure base is initialized before + baseType.Module->TypeNameToTypeIndex.TryGet(baseClass->GetFullName(), *(int32*)&baseType.TypeIndex); + + // So we must special case this flow of a generic class of which its possible the generic base class is not in the same module + if (baseType.TypeIndex == -1 && baseClass->IsGeneric()) + { + auto genericNameIndex = baseClass->GetFullName().FindLast('`'); + // we add 2 because of the way generic names work its `N + auto genericClassName = baseClass->GetFullName().Substring(0, genericNameIndex + 2); + + // We check for the generic class name instead of the baseclass fullname + baseType.Module->TypeNameToTypeIndex.TryGet(genericClassName, *(int32*)&baseType.TypeIndex); + } + if (!baseType) { LOG(Error, "Missing base class for managed class {0} from assembly {1}.", String(typeName), Assembly->ToString()); return; } + + if (baseType.TypeIndex == -1) + { + if (baseType.Module) + LOG(Error, "Missing base class for managed class {0} from assembly {1}.", String(baseClass->GetFullName()), baseType.Module->GetName().ToString()); + else + // Not sure this can happen but never hurts to account for it + LOG(Error, "Missing base class for managed class {0} from unknown assembly.", String(baseClass->GetFullName())); + return; + } + ScriptingTypeHandle nativeType = baseType; while (true) { diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 2727593a0..8c87a5748 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -719,6 +719,13 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa StringAnsi nativeName = _name.EndsWith(".CSharp") ? StringAnsi(_name.Get(), _name.Length() - 7) : StringAnsi(_name); RegisterNativeLibrary(nativeName.Get(), StringAnsi(nativePath).Get()); } +#if USE_EDITOR + // Register the editor module location for Assembly resolver + else + { + RegisterNativeLibrary(_name.Get(), StringAnsi(assemblyPath).Get()); + } +#endif _hasCachedClasses = false; _assemblyPath = assemblyPath; @@ -1597,7 +1604,10 @@ bool InitHostfxr() void* hostfxr = Platform::LoadLibrary(path.Get()); if (hostfxr == nullptr) { - LOG(Fatal, "Failed to load hostfxr library ({0})", path); + if (FileSystem::FileExists(path)) + LOG(Fatal, "Failed to load hostfxr library, possible platform/architecture mismatch with the library. See log for more information. ({0})", path); + else + LOG(Fatal, "Failed to load hostfxr library ({0})", path); return true; } hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)Platform::GetProcAddress(hostfxr, "hostfxr_initialize_for_runtime_config"); @@ -1636,7 +1646,28 @@ bool InitHostfxr() if (rc != 0 || handle == nullptr) { hostfxr_close(handle); - LOG(Fatal, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root)); + if (rc == 0x80008096) // FrameworkMissingFailure + { + String platformStr; + switch (PLATFORM_TYPE) + { + case PlatformType::Windows: + case PlatformType::UWP: + platformStr = PLATFORM_64BITS ? "Windows x64" : "Windows x86"; + break; + case PlatformType::Linux: + platformStr = PLATFORM_ARCH_ARM64 ? "Linux Arm64" : PLATFORM_ARCH_ARM ? "Linux Arm32" : PLATFORM_64BITS ? "Linux x64" : "Linux x86"; + break; + case PlatformType::Mac: + platformStr = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? "macOS Arm64" : PLATFORM_64BITS ? "macOS x64" : "macOS x86"; + break; + default:; + platformStr = ""; + } + LOG(Fatal, "Failed to resolve compatible .NET runtime version in '{0}'. Make sure the correct platform version for runtime is installed ({1})", platformStr, String(init_params.dotnet_root)); + } + else + LOG(Fatal, "Failed to initialize hostfxr: {0:x} ({1})", (unsigned int)rc, String(init_params.dotnet_root)); return true; } diff --git a/Source/Engine/Tests/TestScripting.cs b/Source/Engine/Tests/TestScripting.cs index fd94b8017..93c6637fe 100644 --- a/Source/Engine/Tests/TestScripting.cs +++ b/Source/Engine/Tests/TestScripting.cs @@ -19,7 +19,7 @@ namespace FlaxEngine.Tests { var result = 0; var libraryName = "FlaxEngine"; - var library = NativeLibrary.Load(Interop.NativeInterop.nativeLibraryPaths[libraryName]); + var library = NativeLibrary.Load(Interop.NativeInterop.libraryPaths[libraryName]); if (library == IntPtr.Zero) return -1; var types = typeof(FlaxEngine.Object).Assembly.GetTypes(); diff --git a/Source/Engine/UI/GUI/Common/Slider.cs b/Source/Engine/UI/GUI/Common/Slider.cs index d7324ae0e..7ea2accef 100644 --- a/Source/Engine/UI/GUI/Common/Slider.cs +++ b/Source/Engine/UI/GUI/Common/Slider.cs @@ -60,6 +60,7 @@ public class Slider : ContainerControl private float _thumbCenter; private Float2 _thumbSize = new Float2(16, 16); private bool _isSliding; + private bool _mouseOverThumb; /// /// Gets or sets the value (normalized to range 0-100). @@ -163,21 +164,27 @@ public class Slider : ContainerControl public IBrush FillTrackBrush { get; set; } /// - /// The color of the slider thumb when it's not selected + /// The color of the slider thumb when it's not selected. /// [EditorDisplay("Thumb Style"), EditorOrder(2030), Tooltip("The color of the slider thumb when it's not selected."), ExpandGroups] public Color ThumbColor { get; set; } + + /// + /// The color of the slider thumb when it's highlighted. + /// + [EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's highlighted.")] + public Color ThumbColorHighlighted { get; set; } /// - /// The color of the slider thumb when it's selected + /// The color of the slider thumb when it's selected. /// - [EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's selected.")] + [EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The color of the slider thumb when it's selected.")] public Color ThumbColorSelected { get; set; } /// /// Gets or sets the brush used for slider thumb drawing. /// - [EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The brush of the slider thumb.")] + [EditorDisplay("Thumb Style"), EditorOrder(2033), Tooltip("The brush of the slider thumb.")] public IBrush ThumbBrush { get; set; } /// @@ -222,6 +229,7 @@ public class Slider : ContainerControl TrackFillLineColor = style.LightBackground; ThumbColor = style.BackgroundNormal; ThumbColorSelected = style.BackgroundSelected; + ThumbColorHighlighted = style.BackgroundHighlighted; UpdateThumb(); } @@ -270,7 +278,7 @@ public class Slider : ContainerControl } // Draw thumb - var thumbColor = _isSliding ? ThumbColorSelected : ThumbColor; + var thumbColor = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor); if (ThumbBrush != null) ThumbBrush.Draw(_thumbRect, thumbColor); else @@ -317,6 +325,7 @@ public class Slider : ContainerControl /// public override void OnMouseMove(Float2 location) { + _mouseOverThumb = _thumbRect.Contains(location); if (_isSliding) { // Update sliding diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index b825f5ac1..6a9aa7669 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1340,6 +1340,7 @@ namespace Flax.Build.Bindings public static class NativeToManaged { public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged)); + public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.NativeToManaged.Free(unmanaged); } #if FLAX_EDITOR @@ -1347,6 +1348,7 @@ namespace Flax.Build.Bindings #endif public static class ManagedToNative { + public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged)); public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed); public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.ManagedToNative.Free(unmanaged); } @@ -1668,6 +1670,7 @@ namespace Flax.Build.Bindings contents.Append(indent).AppendLine("[HideInEditor]"); contents.Append(indent).AppendLine("public static class NativeToManaged").Append(indent).AppendLine("{"); contents.Append(indent2).AppendLine($"public static {structureInfo.Name} ConvertToManaged({structureInfo.Name}Internal unmanaged) => {marshallerName}.ToManaged(unmanaged);"); + contents.Append(indent2).AppendLine($"public static {structureInfo.Name}Internal ConvertToUnmanaged({structureInfo.Name} managed) => {marshallerName}.ToNative(managed);"); contents.Append(indent2).AppendLine($"public static void Free({structureInfo.Name}Internal unmanaged)"); contents.Append(indent2).AppendLine("{").Append(indent3).AppendLine(freeContents2.Replace("\n", "\n" + indent3).ToString().TrimEnd()).Append(indent2).AppendLine("}"); contents.Append(indent).AppendLine("}"); @@ -1676,6 +1679,7 @@ namespace Flax.Build.Bindings if (buildData.Target != null && buildData.Target.IsEditor) contents.Append(indent).AppendLine("[HideInEditor]"); contents.Append(indent).AppendLine($"public static class ManagedToNative").Append(indent).AppendLine("{"); + contents.Append(indent2).AppendLine($"public static {structureInfo.Name} ConvertToManaged({structureInfo.Name}Internal unmanaged) => {marshallerName}.ToManaged(unmanaged);"); contents.Append(indent2).AppendLine($"public static {structureInfo.Name}Internal ConvertToUnmanaged({structureInfo.Name} managed) => {marshallerName}.ToNative(managed);"); contents.Append(indent2).AppendLine($"public static void Free({structureInfo.Name}Internal unmanaged) => {marshallerName}.Free(unmanaged);"); contents.Append(indent).AppendLine("}"); diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 43c54a92d..c64ee38b3 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -207,6 +207,7 @@ namespace Flax.Build case TargetPlatform.Mac: { #if USE_NETCORE + dotnetPath = Path.Combine(dotnetSdk.RootPath, "dotnet"); cscPath = Path.Combine(dotnetSdk.RootPath, $"sdk/{dotnetSdk.VersionName}/Roslyn/bincore/csc.dll"); referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/ref/net{runtimeVersionShort}/"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/analyzers/dotnet/cs/"); diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index d3a706a43..9230b4d43 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -212,6 +212,15 @@ namespace Flax.Build ridFallback = ""; if (string.IsNullOrEmpty(dotnetPath)) dotnetPath = "/usr/local/share/dotnet/"; + + // Use x64 when cross-compiling from ARM64 + if (architecture == TargetArchitecture.ARM64 && (Configuration.BuildArchitectures != null && Configuration.BuildArchitectures[0] == TargetArchitecture.x64)) + { + rid = "osx-x64"; + dotnetPath = Path.Combine(dotnetPath, "x64"); + architecture = TargetArchitecture.x64; + } + break; } default: throw new InvalidPlatformException(platform); @@ -271,7 +280,7 @@ namespace Flax.Build // Found IsValid = true; - Log.Verbose($"Found .NET SDK {VersionName} (runtime {RuntimeVersionName}) at {RootPath}"); + Log.Info($"Using .NET SDK {VersionName}, runtime {RuntimeVersionName} ({RootPath})"); foreach (var e in _hostRuntimes) Log.Verbose($" - Host Runtime for {e.Key.Key} {e.Key.Value}"); } diff --git a/Source/Tools/Flax.Build/Platforms/iOS/iOSPlatform.cs b/Source/Tools/Flax.Build/Platforms/iOS/iOSPlatform.cs index 2d7a3372a..d4eaa5006 100644 --- a/Source/Tools/Flax.Build/Platforms/iOS/iOSPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/iOS/iOSPlatform.cs @@ -1,5 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. +using System.IO; + namespace Flax.Build.Platforms { /// @@ -11,6 +13,9 @@ namespace Flax.Build.Platforms /// public override TargetPlatform Target => TargetPlatform.iOS; + /// + public override bool HasRequiredSDKsInstalled { get; } + /// public override bool HasDynamicCodeExecutionSupport => false; @@ -21,11 +26,21 @@ namespace Flax.Build.Platforms { if (Platform.BuildTargetPlatform != TargetPlatform.Mac) return; - if (!HasRequiredSDKsInstalled) + if (!XCode.Instance.IsValid) { Log.Warning("Missing XCode. Cannot build for iOS platform."); return; } + + // We should check and see if the actual iphoneSDK is installed + string iphoneSDKPath = Utilities.ReadProcessOutput("/usr/bin/xcrun", "--sdk iphoneos --show-sdk-path"); + if (string.IsNullOrEmpty(iphoneSDKPath) || !Directory.Exists(iphoneSDKPath)) + { + Log.Warning("Missing iPhoneSDK. Cannot build for iOS platform."); + HasRequiredSDKsInstalled = false; + } + else + HasRequiredSDKsInstalled = true; } ///