// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEngine; namespace FlaxEditor.Surface { public partial class VisjectSurface { /// public override void Update(float deltaTime) { // Update scale var currentScale = _rootControl.Scale.X; if (Mathf.Abs(_targetScale - currentScale) > 0.001f) { var scale = new Float2(Mathf.Lerp(currentScale, _targetScale, deltaTime * 10.0f)); _rootControl.Scale = scale; } // Navigate when mouse is near the edge and is doing sth bool isMovingWithMouse = false; if (IsMovingSelection || (IsConnecting && !IsPrimaryMenuOpened)) { var moveVector = Float2.Zero; float edgeDetectDistance = 22.0f; if (_mousePos.X < edgeDetectDistance) { moveVector.X -= 1; } if (_mousePos.Y < edgeDetectDistance) { moveVector.Y -= 1; } if (_mousePos.X > Width - edgeDetectDistance) { moveVector.X += 1; } if (_mousePos.Y > Height - edgeDetectDistance) { moveVector.Y += 1; } moveVector.Normalize(); isMovingWithMouse = moveVector.LengthSquared > Mathf.Epsilon; if (isMovingWithMouse) { _rootControl.Location -= moveVector * _moveViewWithMouseDragSpeed; } } _moveViewWithMouseDragSpeed = isMovingWithMouse ? Mathf.Clamp(_moveViewWithMouseDragSpeed + deltaTime * 20.0f, 1.0f, 8.0f) : 1.0f; base.Update(deltaTime); // Batch undo actions if (_batchedUndoActions != null && _batchedUndoActions.Count != 0) { Undo.AddAction(_batchedUndoActions.Count == 1 ? _batchedUndoActions[0] : new MultiUndoAction(_batchedUndoActions)); _batchedUndoActions.Clear(); } } /// /// Draws the surface background. /// protected virtual void DrawBackground() { var background = Style.Background; if (background && background.ResidentMipLevels > 0) { var bSize = background.Size; float bw = bSize.X; float bh = bSize.Y; var pos = Float2.Mod(bSize); if (pos.X > 0) pos.X -= bw; if (pos.Y > 0) pos.Y -= bh; int maxI = Mathf.CeilToInt(Width / bw + 1.0f); int maxJ = Mathf.CeilToInt(Height / bh + 1.0f); for (int i = 0; i < maxI; i++) { for (int j = 0; j < maxJ; j++) { Render2D.DrawTexture(background, new Rectangle(pos.X + i * bw, pos.Y + j * bh, bw, bh), Color.White); } } } } /// /// Draws the selection background. /// /// Called only when user is selecting nodes using rectangle tool. protected virtual void DrawSelection() { var selectionRect = Rectangle.FromPoints(_leftMouseDownPos, _mousePos); Render2D.FillRectangle(selectionRect, Color.Orange * 0.4f); Render2D.DrawRectangle(selectionRect, Color.Orange); } /// /// Draws all the connections between surface nodes. /// /// The current mouse position (in surface-space). protected virtual void DrawConnections(ref Float2 mousePosition) { // Draw all connections at once to boost batching process for (int i = 0; i < Nodes.Count; i++) { Nodes[i].DrawConnections(ref mousePosition); Nodes[i].DrawSelectedConnections(_selectedConnectionIndex); } } /// /// Draws the connecting line. /// /// Called only when user is connecting nodes. protected virtual void DrawConnectingLine() { // Get start position var startPos = _connectionInstigator.ConnectionOrigin; // Check if mouse is over any of box var cmVisible = _activeVisjectCM != null && _activeVisjectCM.Visible; var endPos = cmVisible ? _rootControl.PointFromParent(ref _cmStartPos) : _rootControl.PointFromParent(ref _mousePos); Color lineColor = Style.Colors.Connecting; if (_lastInstigatorUnderMouse != null && !cmVisible) { // Check if can connect objects bool canConnect = _connectionInstigator.CanConnectWith(_lastInstigatorUnderMouse); lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid; endPos = _lastInstigatorUnderMouse.ConnectionOrigin; } // Draw connection _connectionInstigator.DrawConnectingLine(ref startPos, ref endPos, ref lineColor); } /// /// Draws the brackets and connections /// protected virtual void DrawInputBrackets() { var style = FlaxEngine.GUI.Style.Current; var fadedColor = style.ForegroundGrey; foreach (var inputBracket in _inputBrackets) { // Draw brackets var upperLeft = _rootControl.PointToParent(inputBracket.Area.UpperLeft); var bottomRight = _rootControl.PointToParent(inputBracket.Area.BottomRight); var upperRight = new Float2(bottomRight.X, upperLeft.Y); var bottomLeft = new Float2(upperLeft.X, bottomRight.Y); // Calculate control points float height = bottomLeft.Y - upperLeft.Y; float offsetX = height / 10f; var leftControl1 = new Float2(bottomLeft.X - offsetX, bottomLeft.Y); var leftControl2 = new Float2(upperLeft.X - offsetX, upperLeft.Y); // Draw left bracket Render2D.DrawBezier(bottomLeft, leftControl1, leftControl2, upperLeft, style.Foreground, 2.2f); // Calculate control points var rightControl1 = new Float2(bottomRight.X + offsetX, bottomRight.Y); var rightControl2 = new Float2(upperRight.X + offsetX, upperRight.Y); // Draw right bracket Render2D.DrawBezier(bottomRight, rightControl1, rightControl2, upperRight, fadedColor, 2.2f); // Draw connection bezier // X-offset at 75% var bezierStartPoint = new Float2(upperRight.X + offsetX * 0.75f, (upperRight.Y + bottomRight.Y) * 0.5f); var bezierEndPoint = inputBracket.Box.ParentNode.PointToParent(_rootControl.Parent, inputBracket.Box.Center); Elements.OutputBox.DrawConnection(ref bezierStartPoint, ref bezierEndPoint, ref fadedColor); // Debug Area //Rectangle drawRect = Rectangle.FromPoints(upperLeft, bottomRight); //Render2D.FillRectangle(drawRect, Color.Green * 0.5f); } } /// /// Draws the contents of the surface (nodes, connections, comments, etc.). /// protected virtual void DrawContents() { base.Draw(); } /// public override void Draw() { var style = FlaxEngine.GUI.Style.Current; var rect = new Rectangle(Float2.Zero, Size); DrawBackground(); _rootControl.DrawComments(); if (IsSelecting) { DrawSelection(); } // Push surface view transform (scale and offset) Render2D.PushTransform(ref _rootControl._cachedTransform); var features = Render2D.Features; Render2D.Features = Render2D.RenderingFeatures.None; var mousePos = _rootControl.PointFromParent(ref _mousePos); DrawConnections(ref mousePos); if (IsConnecting) { DrawConnectingLine(); } Render2D.Features = features; Render2D.PopTransform(); DrawInputBrackets(); DrawContents(); //Render2D.DrawText(style.FontTitle, string.Format("Scale: {0}", _rootControl.Scale), rect, Enabled ? Color.Red : Color.Black); // Draw border if (ContainsFocus) { Render2D.DrawRectangle(new Rectangle(1, 1, rect.Width - 2, rect.Height - 2), Editor.IsPlayMode ? Color.OrangeRed : style.BackgroundSelected); } // Draw disabled overlay //if (!Enabled) // Render2D.FillRectangle(rect, new Color(0.2f, 0.2f, 0.2f, 0.5f), true); } } }