/// <summary> /// 裁剪挡格数据 /// </summary> /// <param name="ar"></param> /// <param name="listblock"></param> /// <param name="minPos"></param> /// <param name="maxPos"></param> /// <returns></returns> public bool CutBlockArea(StageGateArea ar, ref List <Short2> listblock, ref Short2 minPos, ref Short2 maxPos) { if (ar == null) { return(false); } Float2 min = Float2.Min(ar.leftBottom, ar.rightUp); Float2 max = Float2.Max(ar.leftBottom, ar.rightUp); Short2 min2 = GetIndex(min); Short2 max2 = GetIndex(max); Short2 diff = max2 - min2; int width = diff.x + 1; int height = diff.y + 1; maxPos = min2; minPos = max2; List <Short2> list = new List <Short2>(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Short2 pos = new Short2(x + min2.x, y + min2.y); if (CheckBlock(pos) == true) { list.Add(new Short2(x, y)); minPos = Short2.Min(minPos, pos); maxPos = Short2.Max(maxPos, pos); } } } if (listblock == null) { listblock = new List <Short2>(); } listblock.Clear(); foreach (Short2 pos in list) { listblock.Add(pos - (minPos - min2)); } return(true); }
/// <summary> /// Shows the primary menu. /// </summary> /// <param name="location">The location in the Surface Space.</param> /// <param name="moveSurface">If the surface should be moved to accommodate for the menu.</param> /// <param name="input">The user text input for nodes search.</param> public virtual void ShowPrimaryMenu(Float2 location, bool moveSurface = false, string input = null) { if (!CanEdit) { return; } // Check if need to create default context menu (no override specified) if (_activeVisjectCM == null && _cmPrimaryMenu == null) { _activeVisjectCM = _cmPrimaryMenu = CreateDefaultPrimaryMenu(); _activeVisjectCM.ItemClicked += OnPrimaryMenuButtonClick; _activeVisjectCM.VisibleChanged += OnPrimaryMenuVisibleChanged; } if (moveSurface) { const float leftPadding = 20; var delta = Float2.Min(location - leftPadding, Float2.Zero) + Float2.Max((location + _activeVisjectCM.Size) - Size, Float2.Zero); location -= delta; _rootControl.Location -= delta; } _cmStartPos = location; // Offset added in case the user doesn't like the box and wants to quickly get rid of it by clicking OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, _connectionInstigator as Box); if (!string.IsNullOrEmpty(input)) { foreach (char character in input) { // OnKeyDown -> VisjectCM focuses on the text-thingy _activeVisjectCM.OnKeyDown(KeyboardKeys.None); _activeVisjectCM.OnCharInput(character); _activeVisjectCM.OnKeyUp(KeyboardKeys.None); } } }
/// <inheritdoc /> protected override void PerformLayoutBeforeChildren() { base.PerformLayoutBeforeChildren(); // Cache data var tabsSize = Tabs._tabsSize; var clientSize = GetClientArea(); tabsSize = Float2.Min(tabsSize, clientSize.Size); var tabRect = new Rectangle(Float2.Zero, tabsSize); var tabStripOffset = Tabs._orientation == Orientation.Horizontal ? new Float2(tabsSize.X, 0) : new Float2(0, tabsSize.Y); // Arrange tab header controls for (int i = 0; i < Children.Count; i++) { if (Children[i] is TabHeader tabHeader) { tabHeader.Bounds = tabRect; tabRect.Offset(tabStripOffset); } } }
/// <inheritdoc /> public override void Draw() { var style = Style.Current; var mediaBackground = _timeline.MediaBackground; var tracks = _timeline.Tracks; var linesColor = style.BackgroundNormal; var areaLeft = -X; var areaRight = Parent.Width + mediaBackground.ControlsBounds.BottomRight.X; var height = Height; // Calculate the timeline range in the view to optimize background drawing Render2D.PeekClip(out var globalClipping); Render2D.PeekTransform(out var globalTransform); var globalRect = new Rectangle(globalTransform.M31 + areaLeft, globalTransform.M32, areaRight * globalTransform.M11, height * globalTransform.M22); var globalMask = Rectangle.Shared(globalClipping, globalRect); var globalTransformInv = Matrix3x3.Invert(globalTransform); var localRect = Rectangle.FromPoints(Matrix3x3.Transform2D(globalMask.UpperLeft, globalTransformInv), Matrix3x3.Transform2D(globalMask.BottomRight, globalTransformInv)); var localRectMin = localRect.UpperLeft; var localRectMax = localRect.BottomRight; // Draw lines between tracks Render2D.DrawLine(new Float2(areaLeft, 0.5f), new Float2(areaRight, 0.5f), linesColor); for (int i = 0; i < tracks.Count; i++) { var track = tracks[i]; if (track.Visible) { var top = track.Bottom + 0.5f; Render2D.DrawLine(new Float2(areaLeft, top), new Float2(areaRight, top), linesColor); } } // Highlight selected tracks for (int i = 0; i < tracks.Count; i++) { var track = tracks[i]; if (track.Visible && _timeline.SelectedTracks.Contains(track) && _timeline.ContainsFocus) { Render2D.FillRectangle(new Rectangle(areaLeft, track.Top, areaRight, track.Height), style.BackgroundSelected.RGBMultiplied(0.4f)); } } // Setup time axis ticks var minDistanceBetweenTicks = 50.0f; var maxDistanceBetweenTicks = 100.0f; var zoom = Timeline.UnitsPerSecond * _timeline.Zoom; var left = Float2.Min(localRectMin, localRectMax).X; var right = Float2.Max(localRectMin, localRectMax).X; var leftFrame = Mathf.Floor((left - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond; var rightFrame = Mathf.Ceil((right - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond; var min = leftFrame; var max = rightFrame; int smallestTick = 0; int biggestTick = _tickSteps.Length - 1; for (int i = _tickSteps.Length - 1; i >= 0; i--) { // Calculate how far apart these modulo tick steps are spaced float tickSpacing = _tickSteps[i] * _timeline.Zoom; // Calculate the strength of the tick markers based on the spacing _tickStrengths[i] = Mathf.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks)); // Beyond threshold the ticks don't get any bigger or fatter if (_tickStrengths[i] >= 1) { biggestTick = i; } // Do not show small tick markers if (tickSpacing <= minDistanceBetweenTicks) { smallestTick = i; break; } } int tickLevels = biggestTick - smallestTick + 1; // Draw vertical lines for time axis for (int level = 0; level < tickLevels; level++) { float strength = _tickStrengths[smallestTick + level]; if (strength <= Mathf.Epsilon) { continue; } // Draw all ticks int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1); var lStep = _tickSteps[l]; var lNextStep = _tickSteps[l + 1]; int startTick = Mathf.FloorToInt(min / lStep); int endTick = Mathf.CeilToInt(max / lStep); Color lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength); for (int i = startTick; i <= endTick; i++) { if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0)) { continue; } var tick = i * lStep; var time = tick / _timeline.FramesPerSecond; var x = time * zoom + Timeline.StartOffset; // Draw line Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor); } } // Draw selection rectangle if (_isSelecting) { var selectionRect = Rectangle.FromPoints(_selectingStartPos, _mousePos); Render2D.FillRectangle(selectionRect, Color.Orange * 0.4f); Render2D.DrawRectangle(selectionRect, Color.Orange); } DrawChildren(); // Disabled overlay for (int i = 0; i < tracks.Count; i++) { var track = tracks[i]; if (track.DrawDisabled && track.IsExpandedAll) { Render2D.FillRectangle(new Rectangle(areaLeft, track.Top, areaRight, track.Height), new Color(0, 0, 0, 100)); } } // Darken area outside the duration { var outsideDurationAreaColor = new Color(0, 0, 0, 100); var leftSideMin = PointFromParent(Float2.Zero); var leftSideMax = BottomLeft; var rightSideMin = UpperRight; var rightSideMax = PointFromParent(Parent.BottomRight) + mediaBackground.ControlsBounds.BottomRight; Render2D.FillRectangle(new Rectangle(leftSideMin, leftSideMax.X - leftSideMin.X, height), outsideDurationAreaColor); Render2D.FillRectangle(new Rectangle(rightSideMin, rightSideMax.X - rightSideMin.X, height), outsideDurationAreaColor); } // Draw time axis header var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y; var verticalLinesHeaderExtend = Timeline.HeaderTopAreaHeight * 0.5f; var timeShowMode = _timeline.TimeShowMode; Render2D.FillRectangle(new Rectangle(areaLeft, timeAxisHeaderOffset - Timeline.HeaderTopAreaHeight, areaRight - areaLeft, Timeline.HeaderTopAreaHeight), style.Background.RGBMultiplied(0.7f)); for (int level = 0; level < tickLevels; level++) { float strength = _tickStrengths[smallestTick + level]; if (strength <= Mathf.Epsilon) { continue; } // Draw all ticks int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1); var lStep = _tickSteps[l]; var lNextStep = _tickSteps[l + 1]; int startTick = Mathf.FloorToInt(min / lStep); int endTick = Mathf.CeilToInt(max / lStep); Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength); Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength); for (int i = startTick; i <= endTick; i++) { if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0)) { continue; } var tick = i * lStep; var time = tick / _timeline.FramesPerSecond; var x = time * zoom + Timeline.StartOffset; // Header line var lineRect = new Rectangle(x - 0.5f, -verticalLinesHeaderExtend + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend); Render2D.FillRectangle(lineRect, lineColor); // Time label string labelText; switch (timeShowMode) { case Timeline.TimeShowModes.Frames: labelText = tick.ToString("###0", CultureInfo.InvariantCulture); break; case Timeline.TimeShowModes.Seconds: labelText = time.ToString("###0.##'s'", CultureInfo.InvariantCulture); break; case Timeline.TimeShowModes.Time: labelText = TimeSpan.FromSeconds(time).ToString("g"); break; default: throw new ArgumentOutOfRangeException(); } var labelRect = new Rectangle(x + 2, -verticalLinesHeaderExtend + timeAxisHeaderOffset, 50, verticalLinesHeaderExtend); Render2D.DrawText(style.FontSmall, labelText, labelRect, labelColor, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, 0.8f); } } }
private void TryConnect(Box startBox, Box endBox) { if (startBox == null || endBox == null) { if (IsConnecting) { ConnectingEnd(null); } return; } // If the user is patiently waiting for his box to get connected to the newly created one fulfill his wish! _connectionInstigator = startBox; if (!IsConnecting) { ConnectingStart(startBox); } ConnectingEnd(endBox); // Smart-Select next box /* * Output and Output => undefined * Output and Input => Connect and move to next on input-node * Input and Output => Connect and move to next on input-node * Input and Input => undefined, cannot happen */ Box inputBox = endBox.IsOutput ? startBox : endBox; Box nextBox = inputBox.ParentNode.GetNextBox(inputBox); // If we are going backwards and the end-node has an input box we want to edit backwards if (!startBox.IsOutput) { Box endNodeInputBox = endBox.ParentNode.GetBoxes().DefaultIfEmpty(null).FirstOrDefault(b => !b.IsOutput); if (endNodeInputBox != null) { nextBox = endNodeInputBox; } } // TODO: What if we reached the end (nextBox == null)? Do we travel along the nodes? /* * while (nextBox == null && _inputBoxStack.Count > 0) * { * // We found the last box on this node but there are still boxes on previous nodes on the stack * nextBox = GetNextBox(_inputBoxStack.Pop()); * } */ if (nextBox != null) { Select(nextBox.ParentNode); nextBox.ParentNode.SelectBox(nextBox); var padding = new Float2(20); var delta = Float2.Min(_rootControl.PointToParent(nextBox.ParentNode.Location) - padding, Float2.Zero) + Float2.Max((_rootControl.PointToParent(nextBox.ParentNode.BottomRight) + padding) - Size, Float2.Zero); _rootControl.Location -= delta; } }