diff --git a/Source/Editor/Content/GUI/ContentView.cs b/Source/Editor/Content/GUI/ContentView.cs index e0affeedc..06df7d2a2 100644 --- a/Source/Editor/Content/GUI/ContentView.cs +++ b/Source/Editor/Content/GUI/ContentView.cs @@ -536,15 +536,6 @@ namespace FlaxEditor.Content.GUI } } - /// - /// Called when user wants to rename item. - /// - /// The item. - public void OnItemDoubleClickName(ContentItem item) - { - OnRename?.Invoke(item); - } - /// /// Called when user wants to open item. /// @@ -725,19 +716,24 @@ namespace FlaxEditor.Content.GUI case ContentViewType.Tiles: { float defaultItemsWidth = ContentItem.DefaultWidth * viewScale; - int itemsToFit = Mathf.FloorToInt(width / defaultItemsWidth); + int itemsToFit = Mathf.FloorToInt(width / defaultItemsWidth) - 1; + if (itemsToFit < 1) + itemsToFit = 1; float itemsWidth = width / Mathf.Max(itemsToFit, 1); float itemsHeight = itemsWidth / defaultItemsWidth * (ContentItem.DefaultHeight * viewScale); + var flooredItemsWidth = Mathf.Floor(itemsWidth); + var flooredItemsHeight = Mathf.Floor(itemsHeight); + x = itemsToFit == 1 ? 0 : itemsWidth / itemsToFit; for (int i = 0; i < _children.Count; i++) { var c = _children[i]; - c.Bounds = new Rectangle(x, y, itemsWidth, itemsHeight); + c.Bounds = new Rectangle(Mathf.Floor(x), Mathf.Floor(y), flooredItemsWidth, flooredItemsHeight); - x += itemsWidth; + x += itemsWidth + itemsWidth / itemsToFit; if (x + itemsWidth > width) { - x = 0; - y += itemsHeight + 1; + x = itemsToFit == 1 ? 0 : itemsWidth / itemsToFit; + y += itemsHeight + 5; } } if (x > 0) @@ -752,7 +748,7 @@ namespace FlaxEditor.Content.GUI { var c = _children[i]; c.Bounds = new Rectangle(x, y, width, itemsHeight); - y += itemsHeight + 1; + y += itemsHeight + 5; } y += 40.0f; diff --git a/Source/Editor/Content/Items/ContentItem.cs b/Source/Editor/Content/Items/ContentItem.cs index d887c304e..1cc6d480e 100644 --- a/Source/Editor/Content/Items/ContentItem.cs +++ b/Source/Editor/Content/Items/ContentItem.cs @@ -690,18 +690,9 @@ namespace FlaxEditor.Content public override bool OnMouseDoubleClick(Float2 location, MouseButton button) { Focus(); - - // Check if clicked on name area (and can be renamed) - if (CanRename && TextRectangle.Contains(ref location)) - { - // Rename - (Parent as ContentView).OnItemDoubleClickName(this); - } - else - { - // Open - (Parent as ContentView).OnItemDoubleClick(this); - } + + // Open + (Parent as ContentView).OnItemDoubleClick(this); return true; } diff --git a/Source/Editor/Content/Tree/ContentTreeNode.cs b/Source/Editor/Content/Tree/ContentTreeNode.cs index 2503cde51..1d70a8252 100644 --- a/Source/Editor/Content/Tree/ContentTreeNode.cs +++ b/Source/Editor/Content/Tree/ContentTreeNode.cs @@ -95,11 +95,19 @@ namespace FlaxEditor.Content { if (!_folder.CanRename) return; - + Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(false); // Start renaming the folder var dialog = RenamePopup.Show(this, HeaderRect, _folder.ShortName, false); dialog.Tag = _folder; - dialog.Renamed += popup => Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text); + dialog.Renamed += popup => + { + Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text); + Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); + }; + dialog.Closed += popup => + { + Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); + }; } /// diff --git a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs index e6e2338d8..0f6996cc4 100644 --- a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs @@ -24,7 +24,7 @@ namespace FlaxEditor.CustomEditors.Dedicated public override void Initialize(LayoutElementsContainer layout) { string[] layerNames = LayersAndTagsSettings.GetCurrentLayers(); - int layersCount = Math.Max(4, layerNames.Length); + int layersCount = layerNames.Length; _checkBoxes = new List(); _layersCount = layersCount; diff --git a/Source/Editor/CustomEditors/GUI/PropertiesList.cs b/Source/Editor/CustomEditors/GUI/PropertiesList.cs index 68c503c1b..9ff1f2533 100644 --- a/Source/Editor/CustomEditors/GUI/PropertiesList.cs +++ b/Source/Editor/CustomEditors/GUI/PropertiesList.cs @@ -31,6 +31,7 @@ namespace FlaxEditor.CustomEditors.GUI private float _splitterValue; private Rectangle _splitterRect; private bool _splitterClicked, _mouseOverSplitter; + private bool _cursorChanged; /// /// Gets or sets the splitter value (always in range [0; 1]). @@ -124,6 +125,18 @@ namespace FlaxEditor.CustomEditors.GUI if (_splitterClicked) { SplitterValue = location.X / Width; + Cursor = CursorType.SizeWE; + _cursorChanged = true; + } + else if (_mouseOverSplitter) + { + Cursor = CursorType.SizeWE; + _cursorChanged = true; + } + else if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; } base.OnMouseMove(location); @@ -162,6 +175,12 @@ namespace FlaxEditor.CustomEditors.GUI { // Clear flag _mouseOverSplitter = false; + + if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; + } base.OnMouseLeave(); } diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index 2edff5c92..1093b50b7 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -155,11 +155,19 @@ namespace FlaxEditor.GUI.ContextMenu if (parent is ContextMenu menu && menu._childCM != null) locationSS.Y += 30.0f * dpiScale; } - if (monitorBounds.Right < rightBottomLocationSS.X) + if (monitorBounds.Right < rightBottomLocationSS.X || _parentCM?.Direction == ContextMenuDirection.LeftDown || _parentCM?.Direction == ContextMenuDirection.LeftUp) { // Direction: left isLeft = true; - locationSS.X -= dpiSize.X; + + if (IsSubMenu && _parentCM != null) + { + locationSS.X -= _parentCM.Width + dpiSize.X; + } + else + { + locationSS.X -= dpiSize.X; + } } } diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs index 13451fc02..4fef7313b 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuChildMenu.cs @@ -26,6 +26,7 @@ namespace FlaxEditor.GUI.ContextMenu : base(parent, text) { Text = text; + CloseMenuOnClick = false; } /// diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs index ff824d76c..5038dab20 100644 --- a/Source/Editor/GUI/Input/ValueBox.cs +++ b/Source/Editor/GUI/Input/ValueBox.cs @@ -56,6 +56,8 @@ namespace FlaxEditor.GUI.Input private Float2 _startSlideLocation; private double _clickStartTime = -1; + private bool _cursorChanged; + private Float2 _mouseClickedPosition; /// /// Occurs when value gets changed. @@ -172,6 +174,11 @@ namespace FlaxEditor.GUI.Input { _isSliding = false; EndMouseCapture(); + if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; + } SlidingEnd?.Invoke(); } @@ -223,6 +230,8 @@ namespace FlaxEditor.GUI.Input UpdateText(); } + Cursor = CursorType.Default; + ResetViewOffset(); } @@ -236,6 +245,12 @@ namespace FlaxEditor.GUI.Input _startSlideLocation = location; _startSlideValue = _value; StartMouseCapture(true); + + // Hide cursor and cache location + Cursor = CursorType.Hidden; + _mouseClickedPosition = location; + _cursorChanged = true; + SlidingStart?.Invoke(); return true; } @@ -249,7 +264,7 @@ namespace FlaxEditor.GUI.Input /// public override void OnMouseMove(Float2 location) { - if (_isSliding) + if (_isSliding && !RootWindow.Window.IsMouseFlippingHorizontally) { // Update sliding var slideLocation = location + Root.TrackingMouseOffset; @@ -257,6 +272,18 @@ namespace FlaxEditor.GUI.Input return; } + // Update cursor type so user knows they can slide value + if (CanUseSliding && SlideRect.Contains(location) && !_isSliding) + { + Cursor = CursorType.SizeWE; + _cursorChanged = true; + } + else if (_cursorChanged && !_isSliding) + { + Cursor = CursorType.Default; + _cursorChanged = false; + } + base.OnMouseMove(location); } @@ -265,7 +292,8 @@ namespace FlaxEditor.GUI.Input { if (button == MouseButton.Left && _isSliding) { - // End sliding + // End sliding and return mouse to original location + Root.MousePosition = ScreenPos + _mouseClickedPosition; EndSliding(); return true; } @@ -281,6 +309,18 @@ namespace FlaxEditor.GUI.Input return base.OnMouseUp(location, button); } + /// + public override void OnMouseLeave() + { + if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; + } + + base.OnMouseLeave(); + } + /// protected override void OnEditBegin() { diff --git a/Source/Editor/GUI/Timeline/GUI/TimelineEdge.cs b/Source/Editor/GUI/Timeline/GUI/TimelineEdge.cs index 0f1da6e9b..b74b47c46 100644 --- a/Source/Editor/GUI/Timeline/GUI/TimelineEdge.cs +++ b/Source/Editor/GUI/Timeline/GUI/TimelineEdge.cs @@ -69,10 +69,10 @@ namespace FlaxEditor.GUI.Timeline.GUI /// public override void OnMouseMove(Float2 location) { - if (_isMoving) + if (_isMoving && !_timeline.RootWindow.Window.IsMouseFlippingHorizontally) { var moveLocation = Root.MousePosition; - var moveLocationDelta = moveLocation - _startMoveLocation; + var moveLocationDelta = moveLocation - _startMoveLocation + _timeline.Root.TrackingMouseOffset.X; var moveDelta = (int)(moveLocationDelta.X / (Timeline.UnitsPerSecond * _timeline.Zoom) * _timeline.FramesPerSecond); var durationFrames = _timeline.DurationFrames; @@ -83,6 +83,7 @@ namespace FlaxEditor.GUI.Timeline.GUI else { _timeline.DurationFrames = _startMoveDuration + moveDelta; + _timeline.MediaBackground.HScrollBar.Value = _timeline.MediaBackground.HScrollBar.Maximum; } if (_timeline.DurationFrames != durationFrames) @@ -140,6 +141,7 @@ namespace FlaxEditor.GUI.Timeline.GUI _timeline.DurationFrames = duration; } _isMoving = false; + _timeline.MediaBackground.HScrollBar.Value = _timeline.MediaBackground.HScrollBar.Maximum; EndMouseCapture(); } diff --git a/Source/Editor/Modules/SceneEditingModule.cs b/Source/Editor/Modules/SceneEditingModule.cs index 9ffbc514f..7b28367ff 100644 --- a/Source/Editor/Modules/SceneEditingModule.cs +++ b/Source/Editor/Modules/SceneEditingModule.cs @@ -450,7 +450,13 @@ namespace FlaxEditor.Modules SelectionDeleteEnd?.Invoke(); if (isSceneTreeFocus) + { Editor.Windows.SceneWin.Focus(); + } + + // fix scene window layout + Editor.Windows.SceneWin.PerformLayout(); + Editor.Windows.SceneWin.PerformLayout(); } /// @@ -514,6 +520,9 @@ namespace FlaxEditor.Modules Undo.AddAction(new MultiUndoAction(pasteAction, selectAction)); OnSelectionChanged(); } + + // Scroll to new selected node while pasting + Editor.Windows.SceneWin.ScrollToSelectedNode(); } /// @@ -611,6 +620,9 @@ namespace FlaxEditor.Modules Undo.AddAction(new MultiUndoAction(undoActions)); OnSelectionChanged(); } + + // Scroll to new selected node while duplicating + Editor.Windows.SceneWin.ScrollToSelectedNode(); } /// diff --git a/Source/Editor/Options/GeneralOptions.cs b/Source/Editor/Options/GeneralOptions.cs index c3f38f34b..5f05cae2c 100644 --- a/Source/Editor/Options/GeneralOptions.cs +++ b/Source/Editor/Options/GeneralOptions.cs @@ -137,9 +137,9 @@ namespace FlaxEditor.Options /// /// Gets or sets an order of script properties/fields in properties panel. /// - [DefaultValue(MembersOrder.Alphabetical)] + [DefaultValue(MembersOrder.Declaration)] [EditorDisplay("Scripting", "Script Members Order"), EditorOrder(503), Tooltip("Order of script properties/fields in properties panel")] - public MembersOrder ScriptMembersOrder { get; set; } = MembersOrder.Alphabetical; + public MembersOrder ScriptMembersOrder { get; set; } = MembersOrder.Declaration; /// /// Gets or sets a value indicating whether automatically save the Visual Script asset editors when starting the play mode in editor. diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs index 82e9c3c77..63043aa91 100644 --- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs +++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs @@ -273,15 +273,26 @@ namespace FlaxEditor.SceneGraph.GUI Select(); + // Disable scrolling of scene view + Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(false); + // Start renaming the actor var dialog = RenamePopup.Show(this, HeaderRect, _actorNode.Name, false); dialog.Renamed += OnRenamed; + dialog.Closed += popup => + { + // Enable scrolling of scene view + Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(true); + }; } private void OnRenamed(RenamePopup renamePopup) { using (new UndoBlock(ActorNode.Root.Undo, Actor, "Rename")) Actor.Name = renamePopup.Text; + + // Enable scrolling of scene view + Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(true); } /// diff --git a/Source/Editor/Surface/Archetypes/Math.cs b/Source/Editor/Surface/Archetypes/Math.cs index 4518a3090..caedbdc2a 100644 --- a/Source/Editor/Surface/Archetypes/Math.cs +++ b/Source/Editor/Surface/Archetypes/Math.cs @@ -47,7 +47,7 @@ namespace FlaxEditor.Surface.Archetypes Description = desc, Flags = NodeFlags.AllGraphs, AlternativeTitles = altTitles, - Size = new Float2(110, 40), + Size = new Float2(140, 40), DefaultType = new ScriptType(inputType), ConnectionsHints = hints, IndependentBoxes = new[] { 0, 1 }, diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 7fc03531e..066ab1c00 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -223,6 +223,22 @@ namespace FlaxEditor.Viewport editor.SceneEditing.SelectionChanged += OnSelectionChanged; + // Initialize snapping enabled from cached values + if (_editor.ProjectCache.TryGetCustomData("TranslateSnapState", out var cachedState)) + TransformGizmo.TranslationSnapEnable = bool.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedState)) + TransformGizmo.RotationSnapEnabled = bool.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("ScaleSnapState", out cachedState)) + TransformGizmo.ScaleSnapEnabled = bool.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("TranslateSnapValue", out cachedState)) + TransformGizmo.TranslationSnapValue = float.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("RotationSnapValue", out cachedState)) + TransformGizmo.RotationSnapValue = float.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("ScaleSnapValue", out cachedState)) + TransformGizmo.ScaleSnapValue = float.Parse(cachedState); + if (_editor.ProjectCache.TryGetCustomData("TransformSpaceState", out cachedState) && Enum.TryParse(cachedState, out TransformGizmoBase.TransformSpace space)) + TransformGizmo.ActiveTransformSpace = space; + // Transform space widget var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true) @@ -528,21 +544,29 @@ namespace FlaxEditor.Viewport private void OnTranslateSnappingToggle(ViewportWidgetButton button) { TransformGizmo.TranslationSnapEnable = !TransformGizmo.TranslationSnapEnable; + // cache value + _editor.ProjectCache.SetCustomData("TranslateSnapState", TransformGizmo.TranslationSnapEnable.ToString()); } private void OnRotateSnappingToggle(ViewportWidgetButton button) { TransformGizmo.RotationSnapEnabled = !TransformGizmo.RotationSnapEnabled; + // cache value + _editor.ProjectCache.SetCustomData("RotationSnapState", TransformGizmo.RotationSnapEnabled.ToString()); } private void OnScaleSnappingToggle(ViewportWidgetButton button) { TransformGizmo.ScaleSnapEnabled = !TransformGizmo.ScaleSnapEnabled; + // cache value + _editor.ProjectCache.SetCustomData("ScaleSnapState", TransformGizmo.ScaleSnapEnabled.ToString()); } private void OnTransformSpaceToggle(ViewportWidgetButton button) { TransformGizmo.ToggleTransformSpace(); + // cache value + _editor.ProjectCache.SetCustomData("TransformSpaceState", TransformGizmo.ActiveTransformSpace.ToString()); } private void OnGizmoModeChanged() @@ -572,6 +596,8 @@ namespace FlaxEditor.Viewport var v = (float)button.Tag; TransformGizmo.ScaleSnapValue = v; _scaleSnapping.Text = v.ToString(); + // cache value + _editor.ProjectCache.SetCustomData("ScaleSnapValue", TransformGizmo.ScaleSnapValue.ToString("N")); } private void OnWidgetScaleSnapShowHide(Control control) @@ -609,6 +635,8 @@ namespace FlaxEditor.Viewport var v = (float)button.Tag; TransformGizmo.RotationSnapValue = v; _rotateSnapping.Text = v.ToString(); + // cache value + _editor.ProjectCache.SetCustomData("RotationSnapValue", TransformGizmo.RotationSnapValue.ToString("N")); } private void OnWidgetRotateSnapShowHide(Control control) @@ -648,6 +676,8 @@ namespace FlaxEditor.Viewport _translateSnapping.Text = "Bounding Box"; else _translateSnapping.Text = v.ToString(); + // cache value + _editor.ProjectCache.SetCustomData("TranslateSnapValue", TransformGizmo.TranslationSnapValue.ToString("N")); } private void OnWidgetTranslateSnapShowHide(Control control) diff --git a/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs b/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs index 3627ef70e..301ccf9b4 100644 --- a/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs +++ b/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs @@ -7,6 +7,7 @@ using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.CustomEditors.Elements; using FlaxEditor.GUI; +using FlaxEditor.GUI.Tree; using FlaxEditor.Viewport.Cameras; using FlaxEditor.Viewport.Previews; using FlaxEngine; @@ -166,8 +167,21 @@ namespace FlaxEditor.Windows.Assets var proxy = (PropertiesProxy)Values[0]; int nodeIndex = (int)checkBox.Tag; proxy.NodesMask[nodeIndex] = checkBox.Checked; + if (Input.GetKey(KeyboardKeys.Shift)) + SetTreeChecked(checkBox.Parent as TreeNode, checkBox.Checked); proxy.Window.MarkAsEdited(); } + + private void SetTreeChecked(TreeNode tree, bool state) + { + foreach (var node in tree.Children) + { + if (node is TreeNode treeNode) + SetTreeChecked(treeNode, state); + else if (node is CheckBox checkBox) + checkBox.Checked = state; + } + } } } diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index 0f9eba0c0..90cd77d11 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -27,6 +27,8 @@ namespace FlaxEditor.Windows private const string ProjectDataLastViewedFolder = "LastViewedFolder"; private bool _isWorkspaceDirty; private SplitPanel _split; + private Panel _contentViewPanel; + private Panel _contentTreePanel; private ContentView _view; private readonly ToolStrip _toolStrip; @@ -95,7 +97,7 @@ namespace FlaxEditor.Windows }; // Split panel - _split = new SplitPanel(options.Options.Interface.ContentWindowOrientation, ScrollBars.Both, ScrollBars.Vertical) + _split = new SplitPanel(options.Options.Interface.ContentWindowOrientation, ScrollBars.None, ScrollBars.None) { AnchorPreset = AnchorPresets.StretchAll, Offsets = new Margin(0, 0, _toolStrip.Bottom, 0), @@ -120,11 +122,20 @@ namespace FlaxEditor.Windows }; _foldersSearchBox.TextChanged += OnFoldersSearchBoxTextChanged; + // Content tree panel + _contentTreePanel = new Panel + { + AnchorPreset = AnchorPresets.StretchAll, + Offsets = new Margin(0, 0, headerPanel.Bottom, 0), + IsScrollable = true, + ScrollBars = ScrollBars.Both, + Parent = _split.Panel1, + }; + // Content structure tree _tree = new Tree(false) { - Y = headerPanel.Bottom, - Parent = _split.Panel1, + Parent = _contentTreePanel, }; _tree.SelectedChanged += OnTreeSelectionChanged; headerPanel.Parent = _split.Panel1; @@ -159,13 +170,23 @@ namespace FlaxEditor.Windows _viewDropdown.Items.Add(((ContentItemSearchFilter)i).ToString()); _viewDropdown.PopupCreate += OnViewDropdownPopupCreate; + // Content view panel + _contentViewPanel = new Panel + { + AnchorPreset = AnchorPresets.StretchAll, + Offsets = new Margin(0, 0, contentItemsSearchPanel.Bottom + 4, 0), + IsScrollable = true, + ScrollBars = ScrollBars.Vertical, + Parent = _split.Panel2, + }; + // Content View _view = new ContentView { AnchorPreset = AnchorPresets.HorizontalStretchTop, - Offsets = new Margin(0, 0, contentItemsSearchPanel.Bottom + 4, 0), + Offsets = new Margin(0, 0, 0, 0), IsScrollable = true, - Parent = _split.Panel2, + Parent = _contentViewPanel, }; _view.OnOpen += Open; _view.OnNavigateBack += NavigateBackward; @@ -271,6 +292,30 @@ namespace FlaxEditor.Windows RefreshView(SelectedNode); } + /// + /// Enables or disables vertical and horizontal scrolling on the content tree panel + /// + /// The state to set scrolling to + public void ScrollingOnTreeView(bool enabled) + { + if (_contentTreePanel.VScrollBar != null) + _contentTreePanel.VScrollBar.ThumbEnabled = enabled; + if (_contentTreePanel.HScrollBar != null) + _contentTreePanel.HScrollBar.ThumbEnabled = enabled; + } + + /// + /// Enables or disables vertical and horizontal scrolling on the content view panel + /// + /// The state to set scrolling to + public void ScrollingOnContentView(bool enabled) + { + if (_contentViewPanel.VScrollBar != null) + _contentViewPanel.VScrollBar.ThumbEnabled = enabled; + if (_contentViewPanel.HScrollBar != null) + _contentViewPanel.HScrollBar.ThumbEnabled = enabled; + } + /// /// Shows popup dialog with UI to rename content item. /// @@ -285,6 +330,7 @@ namespace FlaxEditor.Windows _split.Panel2.VScrollBar.ThumbEnabled = false; if (_split.Panel2.HScrollBar != null) _split.Panel2.HScrollBar.ThumbEnabled = false; + ScrollingOnContentView(false); // Show rename popup var popup = RenamePopup.Show(item, item.TextRectangle, item.ShortName, true); @@ -298,6 +344,7 @@ namespace FlaxEditor.Windows _split.Panel2.VScrollBar.ThumbEnabled = true; if (_split.Panel2.HScrollBar != null) _split.Panel2.HScrollBar.ThumbEnabled = true; + ScrollingOnContentView(true); // Check if was creating new element if (_newElement != null) diff --git a/Source/Editor/Windows/EditGameWindow.cs b/Source/Editor/Windows/EditGameWindow.cs index 737b13728..3c0d40c9d 100644 --- a/Source/Editor/Windows/EditGameWindow.cs +++ b/Source/Editor/Windows/EditGameWindow.cs @@ -150,9 +150,23 @@ namespace FlaxEditor.Windows }; Viewport.Task.ViewFlags = ViewFlags.DefaultEditor; + Editor.SceneEditing.SelectionChanged += OnSelectionChanged; Editor.Scene.ActorRemoved += SceneOnActorRemoved; } + /// + public override void OnEditorStateChanged() + { + base.OnEditorStateChanged(); + + UpdateCameraPreview(); + } + + private void OnSelectionChanged() + { + UpdateCameraPreview(); + } + /// /// Gets a value indicating whether actor pilot feature is active and in use. /// @@ -376,9 +390,6 @@ namespace FlaxEditor.Windows /// public override void Update(float deltaTime) { - // TODO: call camera preview update only on selection change, or state change - UpdateCameraPreview(); - if (Root.GetKeyDown(KeyboardKeys.F12)) { Viewport.TakeScreenshot(); diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index bccba12c2..396bd3747 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -131,6 +131,7 @@ namespace FlaxEditor.Windows private TextBox _searchBox; private Tree _tree; + private Panel _sceneTreePanel; private bool _isUpdatingSelection; private bool _isMouseDown; @@ -143,10 +144,9 @@ namespace FlaxEditor.Windows /// /// The editor. public SceneTreeWindow(Editor editor) - : base(editor, true, ScrollBars.Both) + : base(editor, true, ScrollBars.None) { Title = "Scene"; - ScrollMargin = new Margin(0, 0, 0, 100.0f); // Scene searching query input box var headerPanel = new ContainerControl @@ -165,19 +165,29 @@ namespace FlaxEditor.Windows }; _searchBox.TextChanged += OnSearchBoxTextChanged; + // Scene tree panel + _sceneTreePanel = new Panel + { + AnchorPreset = AnchorPresets.StretchAll, + Offsets = new Margin(0, 0, headerPanel.Bottom, 0), + IsScrollable = true, + ScrollBars = ScrollBars.Both, + Parent = this, + }; + // Create scene structure tree var root = editor.Scene.Root; root.TreeNode.ChildrenIndent = 0; root.TreeNode.Expand(); _tree = new Tree(true) { - Y = headerPanel.Bottom, Margin = new Margin(0.0f, 0.0f, -16.0f, 0.0f), // Hide root node + IsScrollable = true, }; _tree.AddChild(root.TreeNode); _tree.SelectedChanged += Tree_OnSelectedChanged; _tree.RightClick += OnTreeRightClick; - _tree.Parent = this; + _tree.Parent = _sceneTreePanel; headerPanel.Parent = this; // Setup input actions @@ -188,6 +198,32 @@ namespace FlaxEditor.Windows InputActions.Add(options => options.Rename, Rename); } + /// + /// Enables or disables vertical and horizontal scrolling on the scene tree panel. + /// + /// The state to set scrolling to + public void ScrollingOnSceneTreeView(bool enabled) + { + if (_sceneTreePanel.VScrollBar != null) + _sceneTreePanel.VScrollBar.ThumbEnabled = enabled; + if (_sceneTreePanel.HScrollBar != null) + _sceneTreePanel.HScrollBar.ThumbEnabled = enabled; + } + + /// + /// Scrolls to the selected node in the scene tree. + /// + public void ScrollToSelectedNode() + { + // Scroll to node + var nodeSelection = _tree.Selection; + if (nodeSelection.Count != 0) + { + var scrollControl = nodeSelection[nodeSelection.Count - 1]; + _sceneTreePanel.ScrollViewTo(scrollControl); + } + } + private void OnSearchBoxTextChanged() { // Skip events during setup or init stuff diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h index 891061bf5..8099e8437 100644 --- a/Source/Engine/Core/Config/GraphicsSettings.h +++ b/Source/Engine/Core/Config/GraphicsSettings.h @@ -73,7 +73,7 @@ public: /// If checked, Environment Probes will use HDR texture format. Improves quality in very bright scenes at cost of higher memory usage. /// API_FIELD(Attributes = "EditorOrder(1502), EditorDisplay(\"Quality\")") - bool UeeHDRProbes = false; + bool UseHDRProbes = false; /// /// If checked, enables Global SDF rendering. This can be used in materials, shaders, and particles. @@ -119,6 +119,21 @@ public: API_FIELD(Attributes="EditorOrder(10000), EditorDisplay(\"Post Process Settings\", EditorDisplayAttribute.InlineStyle)") PostProcessSettings PostProcessSettings; +private: + /// + /// Renamed UeeHDRProbes into UseHDRProbes + /// [Deprecated on 12.10.2022, expires on 12.10.2024] + /// + API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") bool GetUeeHDRProbes() const + { + return UseHDRProbes; + } + + API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") void SetUeeHDRProbes(bool value) + { + UseHDRProbes = value; + } + public: /// /// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use. diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 6a77fe858..b9f1aeba2 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -3,6 +3,7 @@ #include "GPUDevice.h" #include "RenderTargetPool.h" #include "GPUPipelineState.h" +#include "GPUSwapChain.h" #include "RenderTask.h" #include "RenderTools.h" #include "Graphics.h" @@ -12,7 +13,6 @@ #include "Engine/Content/Assets/Material.h" #include "Engine/Content/Content.h" #include "Engine/Content/SoftAssetReference.h" -#include "Engine/Platform/Windows/WindowsWindow.h" #include "Engine/Render2D/Render2D.h" #include "Engine/Engine/CommandLine.h" #include "Engine/Engine/Engine.h" @@ -408,7 +408,7 @@ void GPUDevice::DrawEnd() for (int32 i = RenderTask::Tasks.Count() - 1; i >= 0; i--) { const auto task = RenderTask::Tasks[i]; - if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain) + if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain && task->SwapChain->IsReady()) { lastWindowIndex = i; break; @@ -421,7 +421,7 @@ void GPUDevice::DrawEnd() for (int32 i = 0; i < RenderTask::Tasks.Count(); i++) { const auto task = RenderTask::Tasks[i]; - if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain) + if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain && task->SwapChain->IsReady()) { bool vsync = useVSync; if (lastWindowIndex != i) diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index a91074ab5..142baa745 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -120,6 +120,25 @@ void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Float2& cameraViewp cameraViewportSpaceLocation = Float2(clipSpaceLocation); } +bool Camera::IsPointOnView(const Vector3& worldSpaceLocation) const +{ + Vector3 cameraUp = GetTransform().GetUp(); + Vector3 cameraForward = GetTransform().GetForward(); + Vector3 directionToPosition = (worldSpaceLocation - GetPosition()).GetNormalized(); + if (Vector3::Dot(cameraForward, directionToPosition) < 0) + return false; + + Quaternion lookAt = Quaternion::LookRotation(directionToPosition, cameraUp); + Vector3 lookAtDirection = lookAt * Vector3::Forward; + Vector3 newWorldLocation = GetPosition() + lookAtDirection; + + Float2 windowSpace; + const Viewport viewport = GetViewport(); + ProjectPoint(newWorldLocation, windowSpace, viewport); + + return windowSpace.X >= 0 && windowSpace.X <= viewport.Size.X && windowSpace.Y >= 0 && windowSpace.Y <= viewport.Size.Y; +} + Ray Camera::ConvertMouseToRay(const Float2& mousePosition) const { return ConvertMouseToRay(mousePosition, GetViewport()); diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h index 2b59ab323..465130110 100644 --- a/Source/Engine/Level/Actors/Camera.h +++ b/Source/Engine/Level/Actors/Camera.h @@ -168,6 +168,13 @@ public: /// The viewport. API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Float2& cameraViewportSpaceLocation, API_PARAM(Ref) const Viewport& viewport) const; + /// + /// Checks if the 3d point of the world is in the camera's field of view. + /// + /// World Position (XYZ). + /// Returns true if the point is within the field of view. + API_FUNCTION() bool IsPointOnView(const Vector3& worldSpaceLocation) const; + /// /// Converts the mouse position to 3D ray. /// diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h index 9782f40bb..ebeeb6b45 100644 --- a/Source/Engine/Platform/Base/WindowBase.h +++ b/Source/Engine/Platform/Base/WindowBase.h @@ -287,6 +287,8 @@ protected: bool _isUsingMouseOffset; Rectangle _mouseOffsetScreenSize; bool _isTrackingMouse; + bool _isHorizontalFlippingMouse; + bool _isVerticalFlippingMouse; bool _isClippingCursor; explicit WindowBase(const CreateWindowSettings& settings); @@ -680,6 +682,22 @@ public: return _isTrackingMouse; } + /// + /// Gets the value indicating if the mouse flipped to the other screen edge horizontally + /// + API_PROPERTY() bool IsMouseFlippingHorizontally() const + { + return _isHorizontalFlippingMouse; + } + + /// + /// Gets the value indicating if the mouse flipped to the other screen edge vertically + /// + API_PROPERTY() bool IsMouseFlippingVertically() const + { + return _isVerticalFlippingMouse; + } + /// /// Ends the mouse tracking. /// diff --git a/Source/Engine/Platform/SettingsBase.cs b/Source/Engine/Platform/SettingsBase.cs index 505195819..ab25592a5 100644 --- a/Source/Engine/Platform/SettingsBase.cs +++ b/Source/Engine/Platform/SettingsBase.cs @@ -1,5 +1,8 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. +using System; +using FlaxEngine; + namespace FlaxEditor.Content.Settings { /// @@ -11,13 +14,24 @@ namespace FlaxEditor.Content.Settings partial class GraphicsSettings { + /// + /// Renamed UeeHDRProbes into UseHDRProbes + /// [Deprecated on 12.10.2022, expires on 12.10.2024] + /// + [Serialize, Obsolete, NoUndo] + private bool UeeHDRProbes + { + get => UseHDRProbes; + set => UseHDRProbes = value; + } + /// /// Initializes a new instance of the . /// public GraphicsSettings() { // Initialize PostFx settings with default options (C# structs don't support it) - PostProcessSettings = FlaxEngine.PostProcessSettings.Default; + PostProcessSettings = PostProcessSettings.Default; } } } diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 0cd6aab95..da7692eeb 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -544,6 +544,8 @@ void WindowsWindow::StartTrackingMouse(bool useMouseScreenOffset) _isTrackingMouse = true; _trackingMouseOffset = Float2::Zero; _isUsingMouseOffset = useMouseScreenOffset; + _isHorizontalFlippingMouse = false; + _isVerticalFlippingMouse = false; int32 x = 0, y = 0, width = 0, height = 0; GetScreenInfo(x, y, width, height); @@ -558,6 +560,8 @@ void WindowsWindow::EndTrackingMouse() if (_isTrackingMouse) { _isTrackingMouse = false; + _isHorizontalFlippingMouse = false; + _isVerticalFlippingMouse = false; ReleaseCapture(); } @@ -824,14 +828,14 @@ LRESULT WindowsWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) const Float2 mousePos(static_cast(WINDOWS_GET_X_LPARAM(lParam)), static_cast(WINDOWS_GET_Y_LPARAM(lParam))); Float2 mousePosition = ClientToScreen(mousePos); Float2 newMousePosition = mousePosition; - if (mousePosition.X <= desktopLocation.X + 2) - newMousePosition.X = desktopSize.X - 2; - else if (mousePosition.X >= desktopSize.X - 1) - newMousePosition.X = desktopLocation.X + 2; - if (mousePosition.Y <= desktopLocation.Y + 2) - newMousePosition.Y = desktopSize.Y - 2; - else if (mousePosition.Y >= desktopSize.Y - 1) - newMousePosition.Y = desktopLocation.Y + 2; + if (_isHorizontalFlippingMouse = mousePosition.X <= desktopLocation.X + 2) + newMousePosition.X = desktopSize.X - 3; + else if (_isHorizontalFlippingMouse = mousePosition.X >= desktopSize.X - 1) + newMousePosition.X = desktopLocation.X + 3; + if (_isVerticalFlippingMouse = mousePosition.Y <= desktopLocation.Y + 2) + newMousePosition.Y = desktopSize.Y - 3; + else if (_isVerticalFlippingMouse = mousePosition.Y >= desktopSize.Y - 1) + newMousePosition.Y = desktopLocation.Y + 3; if (!Float2::NearEqual(mousePosition, newMousePosition)) { _trackingMouseOffset -= newMousePosition - mousePosition; diff --git a/Source/Engine/Renderer/ProbesRenderer.cpp b/Source/Engine/Renderer/ProbesRenderer.cpp index 51791edd3..c1c273de8 100644 --- a/Source/Engine/Renderer/ProbesRenderer.cpp +++ b/Source/Engine/Renderer/ProbesRenderer.cpp @@ -204,7 +204,7 @@ int32 ProbesRenderer::Entry::GetResolution() const PixelFormat ProbesRenderer::Entry::GetFormat() const { - return GraphicsSettings::Get()->UeeHDRProbes ? PixelFormat::R11G11B10_Float : PixelFormat::R8G8B8A8_UNorm; + return GraphicsSettings::Get()->UseHDRProbes ? PixelFormat::R11G11B10_Float : PixelFormat::R8G8B8A8_UNorm; } int32 ProbesRenderer::GetBakeQueueSize() diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index 8384741bc..86c242609 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -948,6 +948,10 @@ namespace FlaxEngine.GUI { // Set flag _isDragOver = true; + + // Hide tooltip + Tooltip?.Hide(); + return DragDropEffect.None; } diff --git a/Source/Engine/UI/GUI/Panels/SplitPanel.cs b/Source/Engine/UI/GUI/Panels/SplitPanel.cs index 8772c78e6..2a46846e8 100644 --- a/Source/Engine/UI/GUI/Panels/SplitPanel.cs +++ b/Source/Engine/UI/GUI/Panels/SplitPanel.cs @@ -23,6 +23,7 @@ namespace FlaxEngine.GUI private float _splitterValue; private Rectangle _splitterRect; private bool _splitterClicked, _mouseOverSplitter; + private bool _cursorChanged; /// /// The first panel (left or upper based on Orientation). @@ -161,6 +162,18 @@ namespace FlaxEngine.GUI if (_splitterClicked) { SplitterValue = _orientation == Orientation.Horizontal ? location.X / Width : location.Y / Height; + Cursor = _orientation == Orientation.Horizontal ? CursorType.SizeWE : CursorType.SizeNS; + _cursorChanged = true; + } + else if (_mouseOverSplitter) + { + Cursor = _orientation == Orientation.Horizontal ? CursorType.SizeWE : CursorType.SizeNS; + _cursorChanged = true; + } + else if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; } base.OnMouseMove(location); @@ -197,6 +210,11 @@ namespace FlaxEngine.GUI { // Clear flag _mouseOverSplitter = false; + if (_cursorChanged) + { + Cursor = CursorType.Default; + _cursorChanged = false; + } base.OnMouseLeave(); } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index eaafcc615..ac22fb16a 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -919,10 +919,8 @@ namespace Flax.Build.Bindings // Properties foreach (var propertyInfo in classInfo.Properties) { - if (propertyInfo.IsHidden) + if (propertyInfo.IsHidden || !useUnmanaged) continue; - if (!useUnmanaged) - throw new NotImplementedException("TODO: support properties inside non-static and non-scripting API class types."); contents.AppendLine(); GenerateCSharpComment(contents, indent, propertyInfo.Comment, true); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index dc5190f36..921043e1d 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1440,6 +1440,11 @@ namespace Flax.Build.Bindings continue; if (GenerateCppAutoSerializationSkip(buildData, typeInfo, propertyInfo, propertyInfo.Type)) continue; + CppAutoSerializeProperties.Add(propertyInfo); + + // Skip writing deprecated properties (read-only deserialization to allow reading old data) + if (propertyInfo.HasAttribute("Obsolete")) + continue; contents.Append(" {"); contents.Append(" const auto"); @@ -1456,7 +1461,6 @@ namespace Flax.Build.Bindings contents.Append($"stream.JKEY(\"{propertyInfo.Name}\"); Serialization::Serialize(stream, value, nullptr);"); contents.Append(" }"); contents.Append('}').AppendLine(); - CppAutoSerializeProperties.Add(propertyInfo); } } else if (structureInfo != null) @@ -1488,14 +1492,14 @@ namespace Flax.Build.Bindings foreach (var propertyInfo in CppAutoSerializeProperties) { - contents.Append(" {"); - contents.Append($" const auto e = SERIALIZE_FIND_MEMBER(stream, \"{propertyInfo.Name}\");"); - contents.Append(" if (e != stream.MemberEnd()) {"); - contents.Append($" auto p = {propertyInfo.Getter.Name}();"); - contents.Append(" Serialization::Deserialize(e->value, p, modifier);"); - contents.Append($" {propertyInfo.Setter.Name}(p);"); - contents.Append(" }"); - contents.Append('}').AppendLine(); + contents.AppendLine(" {"); + contents.AppendLine($" const auto e = SERIALIZE_FIND_MEMBER(stream, \"{propertyInfo.Name}\");"); + contents.AppendLine(" if (e != stream.MemberEnd()) {"); + contents.AppendLine($" auto p = {propertyInfo.Getter.Name}();"); + contents.AppendLine(" Serialization::Deserialize(e->value, p, modifier);"); + contents.AppendLine($" {propertyInfo.Setter.Name}(p);"); + contents.AppendLine(" }"); + contents.AppendLine(" }"); } contents.Append('}').AppendLine(); diff --git a/Source/Tools/Flax.Build/Build/Builder.Projects.cs b/Source/Tools/Flax.Build/Build/Builder.Projects.cs index 21aa25788..42bda3ea5 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Projects.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Projects.cs @@ -433,7 +433,7 @@ namespace Flax.Build else if (dependencyModule.BinaryModuleName == "FlaxEngine") { // TODO: instead of this hack find a way to reference the prebuilt target bindings binary (example: game C# project references FlaxEngine C# prebuilt dll) - project.CSharp.FileReferences.Add(Path.Combine(Globals.EngineRoot, "Binaries/Editor/Win64/Development/FlaxEngine.CSharp.dll")); + project.CSharp.FileReferences.Add(Path.Combine(Globals.EngineRoot, Platform.GetEditorBinaryDirectory(), "Development/FlaxEngine.CSharp.dll")); } } } diff --git a/Source/Tools/Flax.Build/Build/Platform.cs b/Source/Tools/Flax.Build/Build/Platform.cs index 72e6454a4..99edc7889 100644 --- a/Source/Tools/Flax.Build/Build/Platform.cs +++ b/Source/Tools/Flax.Build/Build/Platform.cs @@ -245,6 +245,24 @@ namespace Flax.Build return toolchain; } + /// + /// Gets path to the current platform binary directory + /// + public static string GetEditorBinaryDirectory() + { + var subdir = "Binaries/Editor/"; + switch (Platform.BuildTargetPlatform) + { + case TargetPlatform.Windows: + return subdir + "Win64"; + case TargetPlatform.Linux: + return subdir + "Linux"; + case TargetPlatform.Mac: + return subdir + "Mac"; + } + throw new NotImplementedException(); + } + /// /// Creates the project files generator for the specified project format. /// diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 55f3d138d..4c3f63b0c 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -39,6 +39,12 @@ namespace Flax.Build [CommandLine("deploy", "Runs the deploy tool.")] public static bool Deploy = false; + /// + /// Compresses deployed files. + /// + [CommandLine("deployDontCompress", "Skips compressing deployed files, and keeps files.")] + public static bool DontCompress = false; + /// /// Builds the targets. Builds all the targets, use to select a custom set of targets for the build. /// diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs index ad94da918..c4ca880f7 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using Flax.Build; +using Flax.Build.Platforms; namespace Flax.Deploy { @@ -126,21 +127,24 @@ namespace Flax.Deploy DeployFile(RootPath, OutputPath, "Flax.flaxproj"); // Compress + if (Configuration.DontCompress) + return; + Log.Info(string.Empty); Log.Info("Compressing editor files..."); string editorPackageZipPath; - if (Platform.BuildTargetPlatform == TargetPlatform.Linux) + var unix = Platform.BuildTargetPlatform == TargetPlatform.Linux || Platform.BuildTargetPlatform == TargetPlatform.Mac; + if (unix) { - // Use system tool (preserves executable file attributes and link files) - editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "FlaxEditorLinux.zip"); - Utilities.FileDelete(editorPackageZipPath); - Utilities.Run("zip", "Editor.zip -r .", null, OutputPath, Utilities.RunOptions.ThrowExceptionOnError); - File.Move(Path.Combine(OutputPath, "Editor.zip"), editorPackageZipPath); + var zipEofPath = UnixPlatform.Which("zip"); + unix = File.Exists(zipEofPath); + if (!unix) + Log.Verbose("Using .NET compressing"); } - else if (Platform.BuildTargetPlatform == TargetPlatform.Mac) + if (unix) { // Use system tool (preserves executable file attributes and link files) - editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "FlaxEditorMac.zip"); + editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, $"FlaxEditor{Enum.GetName(typeof(TargetPlatform), Platform.BuildTargetPlatform)}.zip"); Utilities.FileDelete(editorPackageZipPath); Utilities.Run("zip", "Editor.zip -r .", null, OutputPath, Utilities.RunOptions.ThrowExceptionOnError); File.Move(Path.Combine(OutputPath, "Editor.zip"), editorPackageZipPath); @@ -189,13 +193,14 @@ namespace Flax.Deploy private static void DeployEditorBinaries(TargetConfiguration configuration) { + var binariesSubDir = Path.Combine(Platform.GetEditorBinaryDirectory(), configuration.ToString()); + var src = Path.Combine(RootPath, binariesSubDir); + var dst = Path.Combine(OutputPath, binariesSubDir); + Directory.CreateDirectory(dst); + if (Platform.BuildTargetPlatform == TargetPlatform.Windows) { - var binariesSubDir = "Binaries/Editor/Win64/" + configuration; - var src = Path.Combine(RootPath, binariesSubDir); - var dst = Path.Combine(OutputPath, binariesSubDir); var dstDebug = Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols/Win64/" + configuration); - Directory.CreateDirectory(dst); Directory.CreateDirectory(dstDebug); // Validate that build editor app has a valid version number @@ -229,11 +234,6 @@ namespace Flax.Deploy } else if (Platform.BuildTargetPlatform == TargetPlatform.Linux) { - var binariesSubDir = "Binaries/Editor/Linux/" + configuration; - var src = Path.Combine(RootPath, binariesSubDir); - var dst = Path.Combine(OutputPath, binariesSubDir); - Directory.CreateDirectory(dst); - // Deploy binaries DeployFile(src, dst, "FlaxEditor"); DeployFile(src, dst, "FlaxEditor.Build.json"); @@ -253,11 +253,6 @@ namespace Flax.Deploy } else if (Platform.BuildTargetPlatform == TargetPlatform.Mac) { - var binariesSubDir = "Binaries/Editor/Mac/" + configuration; - var src = Path.Combine(RootPath, binariesSubDir); - var dst = Path.Combine(OutputPath, binariesSubDir); - Directory.CreateDirectory(dst); - // Deploy binaries DeployFile(src, dst, "FlaxEditor"); DeployFile(src, dst, "FlaxEditor.Build.json"); @@ -274,10 +269,6 @@ namespace Flax.Deploy Utilities.Run("strip", "libmonosgen-2.0.1.dylib", null, dst, Utilities.RunOptions.None); Utilities.Run("strip", "libMoltenVK.dylib", null, dst, Utilities.RunOptions.None); } - else - { - throw new NotImplementedException(); - } } } } diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs index 78e6183bb..9a6d372d2 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployment.Platforms.cs @@ -63,6 +63,7 @@ namespace Flax.Deploy } // Compress + if (!Configuration.DontCompress) { Log.Info("Compressing platform files..."); @@ -84,10 +85,10 @@ namespace Flax.Deploy #endif Log.Info(string.Format("Compressed {0} package size: {1}", platformName, Utilities.GetFileSize(packageZipPath))); - } - // Remove files (only zip package is used) - Utilities.DirectoryDelete(dst); + // Remove files (only zip package is used) + Utilities.DirectoryDelete(dst); + } Log.Info(string.Empty); } diff --git a/Source/Tools/Flax.Build/Platforms/Linux/LinuxPlatform.cs b/Source/Tools/Flax.Build/Platforms/Linux/LinuxPlatform.cs index 1d0433f50..ced516a54 100644 --- a/Source/Tools/Flax.Build/Platforms/Linux/LinuxPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/Linux/LinuxPlatform.cs @@ -58,7 +58,7 @@ namespace Flax.Build.Platforms if (Compiler != null) { // System compiler - ToolchainRoot = string.Empty; + ToolchainRoot = "/"; Log.Verbose($"Using native Linux toolchain (compiler {Compiler})"); HasRequiredSDKsInstalled = true; } diff --git a/Source/Tools/Flax.Build/Platforms/Linux/LinuxToolchain.cs b/Source/Tools/Flax.Build/Platforms/Linux/LinuxToolchain.cs index ede17b639..2904b89a7 100644 --- a/Source/Tools/Flax.Build/Platforms/Linux/LinuxToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/Linux/LinuxToolchain.cs @@ -23,9 +23,16 @@ namespace Flax.Build.Platforms : base(platform, architecture, platform.ToolchainRoot, platform.Compiler) { // Setup system paths - SystemIncludePaths.Add(Path.Combine(ToolsetRoot, "usr", "include")); - SystemIncludePaths.Add(Path.Combine(ToolsetRoot, "include", "c++", "5.2.0")); - SystemIncludePaths.Add(Path.Combine(ToolsetRoot, "lib", "clang", ClangVersion.Major.ToString(), "include")); + var includePath = Path.Combine(ToolsetRoot, "usr", "include"); + SystemIncludePaths.Add(includePath); + var cppIncludePath = Path.Combine(includePath, "c++", ClangVersion.ToString()); + if (Directory.Exists(cppIncludePath)) + SystemIncludePaths.Add(cppIncludePath); + var clangLibPath = Path.Combine(ToolsetRoot, "usr", "lib", "clang"); + var clangIncludePath = Path.Combine(clangLibPath, ClangVersion.Major.ToString(), "include"); + if (!Directory.Exists(clangIncludePath)) + clangIncludePath = Path.Combine(clangLibPath, ClangVersion.ToString(), "include"); + SystemIncludePaths.Add(clangIncludePath); } /// diff --git a/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs index f218a9a4f..cb0e5311e 100644 --- a/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/ProjectGenerator.cs @@ -138,7 +138,9 @@ namespace Flax.Build.Projects default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } - case ProjectFormat.VisualStudioCode: return new VisualStudioCodeProjectGenerator(); + case ProjectFormat.VisualStudioCode: return type == TargetType.DotNet + ? (ProjectGenerator)new CSProjectGenerator(VisualStudioVersion.VisualStudio2015) + : (ProjectGenerator)new VisualStudioCodeProjectGenerator(); case ProjectFormat.XCode: return new XCodeProjectGenerator(); case ProjectFormat.Custom: if (CustomProjectTypes.TryGetValue(Configuration.ProjectFormatCustom, out var factory)) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs index f726ea0c4..f3a4a0e8e 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs @@ -547,6 +547,10 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddField("**/Output", true); json.AddField("**/*.flax", true); json.EndObject(); + + // Extension settings + json.AddField("omnisharp.useModernNet", false); + json.EndRootObject(); json.Save(Path.Combine(vsCodeFolder, "settings.json"));