/// <summary> /// Attempts to find an event under the provided coordinates. /// </summary> /// <param name="pixelCoords">Coordinates relative to the layout the GUI element is on.</param> /// <param name="eventIdx">Index of the event that was clicked on. Index references the events array as provided /// to <see cref="SetEvents"/>. Only valid if method returns true.</param> /// <returns>True if an event was found under the coordinates, false otherwise.</returns> public bool FindEvent(Vector2I pixelCoords, out int eventIdx) { Rect2I bounds = canvas.Bounds; if (pixelCoords.x < (bounds.x + PADDING) || pixelCoords.x >= (bounds.x + bounds.width - PADDING) || pixelCoords.y < bounds.y || pixelCoords.y >= (bounds.y + bounds.height)) { eventIdx = -1; return false; } Vector2I relativeCoords = pixelCoords - new Vector2I(bounds.x, bounds.y); for (int i = 0; i < events.Length; i++) { AnimationEvent evnt = events[i]; int xPos = (int)(((evnt.Time - rangeOffset) / GetRange()) * drawableWidth) + PADDING; if (relativeCoords.x >= (xPos - EVENT_HALF_WIDTH) && relativeCoords.x <= (xPos + EVENT_HALF_WIDTH)) { eventIdx = i; return true; } } eventIdx = -1; return false; }
/// <summary> /// Returns true if the rectangle contains the provided point. /// </summary> /// <param name="point">Point to check if it is in rectangle.</param> /// <returns>True if the point within rectangle bounds.</returns> public bool Contains(Vector2I point) { if(point.x >= x && point.x < (x + width)) { if(point.y >= y && point.y < (y + height)) return true; } return false; }
private static extern void Internal_GetPointerDelta(out Vector2I delta);
/// <summary> /// Attempts to find a scene object under the provided position, while also returning the world position and normal /// of the point that was hit. /// </summary> /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param> /// <param name="data">Position and normal on the object surface at the point that was hit.</param> /// <param name="ignoreSceneObjects">Optional set of objects to ignore during scene picking.</param> /// <returns>The object the pointer is snapping to.</returns> internal SceneObject Snap(Vector2I pointerPos, out SnapData data, SceneObject[] ignoreSceneObjects = null) { return Internal_Snap(mCachedPtr, ref pointerPos, out data, ignoreSceneObjects); }
private static extern SceneObject Internal_Snap(IntPtr thisPtr, ref Vector2I pointerPos, out SnapData data, SceneObject[] ignoreRenderables);
/// <summary> /// Handles input over the color box, moving the handle as needed. /// </summary> /// <param name="windowPos">Position of the pointer relative to the color picker window.</param> public void UpdateInput(Vector2I windowPos) { if (Input.IsPointerButtonHeld(PointerButton.Left)) { Rect2I bounds = guiTexture.Bounds; if (bounds.Contains(windowPos)) { Vector2 newValue = Vector2.Zero; newValue.x = (windowPos.x - bounds.x) / (float)bounds.width; newValue.y = 1.0f - (windowPos.y - bounds.y) / (float)bounds.height; SetValue(newValue); } } }
private static extern void Internal_DrawLine(IntPtr nativeInstance, ref Vector2I a, ref Vector2I b, ref Color color, byte depth);
private void OnEditorUpdate() { if (HasFocus) { if (!Input.IsPointerButtonHeld(PointerButton.Right)) { if (VirtualInput.IsButtonDown(EditorApplication.DuplicateKey)) DuplicateSelection(); else if (VirtualInput.IsButtonDown(EditorApplication.DeleteKey)) DeleteSelection(); else if (VirtualInput.IsButtonDown(toggleProfilerOverlayKey)) EditorSettings.SetBool(ProfilerOverlayActiveKey, !EditorSettings.GetBool(ProfilerOverlayActiveKey)); else if(VirtualInput.IsButtonDown(viewToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.View; else if(VirtualInput.IsButtonDown(moveToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Move; else if(VirtualInput.IsButtonDown(rotateToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Rotate; else if(VirtualInput.IsButtonDown(scaleToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Scale; } } // Refresh GUI buttons if needed (in case someones changes the values from script) if (editorSettingsHash != EditorSettings.Hash) { UpdateButtonStates(); UpdateProfilerOverlay(); editorSettingsHash = EditorSettings.Hash; } // Update scene view handles and selection sceneGizmos.Draw(); sceneGrid.Draw(); bool handleActive = sceneHandles.IsActive() || sceneAxesGUI.IsActive(); Vector2I scenePos; bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos); bool dragResult = false; if (Input.IsPointerButtonUp(PointerButton.Left)) { dragResult = EndDragSelection(); if (sceneHandles.IsActive()) sceneHandles.ClearSelection(); if (sceneAxesGUI.IsActive()) sceneAxesGUI.ClearSelection(); } else if (Input.IsPointerButtonDown(PointerButton.Left)) { mouseDownPosition = scenePos; } bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress; draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource; if (draggedOver) { if (DragDrop.DropInProgress) { dragActive = false; if (draggedSO != null) { Selection.SceneObject = draggedSO; EditorApplication.SetSceneDirty(); } draggedSO = null; } else { if (!dragActive) { dragActive = true; ResourceDragDropData dragData = (ResourceDragDropData)DragDrop.Data; string[] draggedPaths = dragData.Paths; for (int i = 0; i < draggedPaths.Length; i++) { ResourceMeta meta = ProjectLibrary.GetMeta(draggedPaths[i]); if (meta != null) { if (meta.ResType == ResourceType.Mesh) { if (!string.IsNullOrEmpty(draggedPaths[i])) { string meshName = Path.GetFileNameWithoutExtension(draggedPaths[i]); draggedSO = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\""); Mesh mesh = ProjectLibrary.Load<Mesh>(draggedPaths[i]); Renderable renderable = draggedSO.AddComponent<Renderable>(); renderable.Mesh = mesh; if (mesh != null) draggedSOOffset = mesh.Bounds.Box.Center; else draggedSOOffset = Vector3.Zero; } break; } else if (meta.ResType == ResourceType.Prefab) { if (!string.IsNullOrEmpty(draggedPaths[i])) { Prefab prefab = ProjectLibrary.Load<Prefab>(draggedPaths[i]); draggedSO = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name); if (draggedSO != null) { AABox draggedObjBounds = EditorUtility.CalculateBounds(draggedSO); draggedSOOffset = draggedObjBounds.Center; } else draggedSOOffset = Vector3.Zero; } break; } } } } if (draggedSO != null) { if (Input.IsButtonHeld(ButtonCode.Space)) { SnapData snapData; sceneSelection.Snap(scenePos, out snapData, new SceneObject[] {draggedSO}); Quaternion q = Quaternion.FromToRotation(Vector3.YAxis, snapData.normal); draggedSO.Position = snapData.position; draggedSO.Rotation = q; } else { Ray worldRay = camera.ViewportToWorldRay(scenePos); draggedSO.Position = worldRay * DefaultPlacementDepth - draggedSOOffset; } } } return; } else { if (dragActive) { dragActive = false; if (draggedSO != null) { draggedSO.Destroy(); draggedSO = null; } } } if (HasContentFocus || IsPointerHovering) { cameraController.EnableInput(true); if (inBounds && HasContentFocus) { if (Input.IsPointerButtonDown(PointerButton.Left)) { Rect2I sceneAxesGUIBounds = new Rect2I(Width - HandleAxesGUISize - HandleAxesGUIPaddingX, HandleAxesGUIPaddingY, HandleAxesGUISize, HandleAxesGUISize); if (sceneAxesGUIBounds.Contains(scenePos)) sceneAxesGUI.TrySelect(scenePos); else sceneHandles.TrySelect(scenePos); } else if (Input.IsPointerButtonHeld(PointerButton.Left) && !handleActive && !dragActive && draggedSO == null && scenePos != mouseDownPosition) { if (isDraggingSelection) UpdateDragSelection(scenePos); else StartDragSelection(scenePos); } else if (Input.IsPointerButtonUp(PointerButton.Left)) { if (!handleActive && !dragActive && !dragResult) { bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl); sceneSelection.PickObject(scenePos, ctrlHeld, new SceneObject[] {draggedSO}); } } } } else cameraController.EnableInput(false); SceneHandles.BeginInput(); sceneHandles.UpdateInput(scenePos, Input.PointerDelta); sceneHandles.Draw(); sceneAxesGUI.UpdateInput(scenePos); sceneAxesGUI.Draw(); SceneHandles.EndInput(); sceneSelection.Draw(); UpdateGridMode(); if (VirtualInput.IsButtonDown(frameKey)) cameraController.FrameSelected(); }
private static extern void Internal_ClipToScreen(IntPtr instance, ref Vector2 value, out Vector2I output);
private static extern void Internal_ScreenToClip(IntPtr instance, ref Vector2I value, out Vector2 output);
private static extern void Internal_ScreenToView(IntPtr instance, ref Vector2I value, float depth, out Vector3 output);
private static extern void Internal_GetPointerPosition(out Vector2I position);
/// <summary> /// Draws a line going from <paramref name="a"/> to <paramref name="b"/>. /// </summary> /// <param name="a">Starting point of the line, relative to the canvas origin (top-left).</param> /// <param name="b">Ending point of the line, relative to the canvas origin (top-left).</param> /// <param name="color">Color of the line.</param> /// <param name="depth">Depth at which to draw the element. Elements with higher depth will be drawn before others. /// Additionally elements of the same type (triangle or line) will be drawn in order they are /// submitted if they share the same depth.</param> public void DrawLine(Vector2I a, Vector2I b, Color color, byte depth = 128) { Internal_DrawLine(mCachedPtr, ref a, ref b, ref color, depth); }
private static extern void Internal_DrawText(IntPtr nativeInstance, string text, ref Vector2I position, IntPtr font, int size, ref Color color, byte depth);
/// <summary> /// Triggers when some pointing device (mouse cursor, touch) button is released. /// </summary> /// <param name="screenPos">Screen position where the input event occurred.</param> /// <param name="delta">Change in movement since last sent event.</param> /// <param name="button">Button that triggered the pointer event. Might be irrelevant depending on event type. /// (for example move events don't correspond to a button.</param> /// <param name="shift">Is shift button on the keyboard being held down.</param> /// <param name="ctrl">Is control button on the keyboard being held down.</param> /// <param name="alt">Is alt button on the keyboard being held down.</param> /// <param name="scrollAmount">If mouse wheel is being scrolled, what is the amount. Only relevant for /// move events.</param> private static void Internal_TriggerPointerReleased(Vector2I screenPos, Vector2I delta, PointerButton button, bool shift, bool ctrl, bool alt, float scrollAmount) { PointerEvent ev = new PointerEvent(screenPos, delta, button, shift, ctrl, alt, scrollAmount); if (OnPointerReleased != null) OnPointerReleased(ev); }
/// <summary> /// Returns the manhattan distance between two points. /// </summary> /// <param name="a">First two dimensional point.</param> /// <param name="b">Second two dimensional point.</param> /// <returns>Manhattan distance between the two points.</returns> public static int Distance(Vector2I a, Vector2I b) { return Math.Abs(b.x - a.x) + Math.Abs(b.y - a.y); }
private static extern void Internal_ScreenToWorldRay(IntPtr instance, ref Vector2I value, out Ray output);
/// <summary> /// Starts a drag operation that displays a selection outline allowing the user to select multiple entries at once. /// </summary> /// <param name="scenePos">Coordinates relative to the scene where the drag originated.</param> private void StartDragSelection(Vector2I scenePos) { isDraggingSelection = true; dragSelectionStart = scenePos; dragSelectionEnd = dragSelectionStart; }
/// <summary> /// Attempts to select a scene object under the pointer position. /// </summary> /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param> /// <param name="controlHeld">Should this selection add to the existing selection, or replace it.</param> internal void PickObject(Vector2I pointerPos, bool controlHeld) { Internal_PickObject(mCachedPtr, ref pointerPos, controlHeld); }
private static extern void Internal_WindowToScreenPos(IntPtr nativeInstance, ref Vector2I position, out Vector2I screenPos);
private static extern void Internal_PickObject(IntPtr thisPtr, ref Vector2I pointerPos, bool controlHeld);
/// <summary> /// Draws a marker for a single event. /// </summary> /// <param name="t">Time to draw the marker at.</param> /// <param name="selected">If true the marker will be drawn as selected.</param> private void DrawEventMarker(float t, bool selected) { int xPos = (int)(((t - rangeOffset) / GetRange()) * drawableWidth) + PADDING; Vector2I a = new Vector2I(xPos - EVENT_HALF_WIDTH, 0); Vector2I b = new Vector2I(xPos + EVENT_HALF_WIDTH, 0); Vector2I c = new Vector2I(xPos + EVENT_HALF_WIDTH, height - 1); Vector2I d = new Vector2I(xPos - EVENT_HALF_WIDTH, height - 1); // Draw square shape Vector2I[] linePoints = { a, b, c, d, a }; Vector2I[] trianglePoints = { b, c, a, d }; Color outerColor = selected ? Color.BansheeOrange : Color.Black; canvas.DrawTriangleStrip(trianglePoints, Color.White, 101); canvas.DrawPolyLine(linePoints, outerColor, 100); }
/// <summary> /// Selects a handle under the pointer position. /// </summary> /// <param name="pointerPos">Position of the pointer relative to the parent GUI panel.</param> public void TrySelect(Vector2I pointerPos) { if (!bounds.Contains(pointerPos)) return; pointerPos.x -= bounds.x; pointerPos.y -= bounds.y; sceneHandles.TrySelect(pointerPos); }
private static extern void Internal_PickObjects(IntPtr thisPtr, ref Vector2I pointerPos, ref Vector2I extents, bool controlHeld, SceneObject[] ignoreRenderables);
/// <summary> /// Updates active handles by moving them as a result of any input. /// </summary> /// <param name="pointerPos">Position of the pointer relative to the parent GUI panel</param> public void UpdateInput(Vector2I pointerPos) { pointerPos.x -= bounds.x; pointerPos.y -= bounds.y; sceneHandles.UpdateInput(pointerPos, Input.PointerDelta); }
/// <summary> /// Attempts to select a scene object in the specified area. /// </summary> /// <param name="pointerPos">Position of the pointer relative to the scene camera viewport.</param> /// <param name="area">Size of the in which objects will be selected, in pixels and relative to /// <paramref name="pointerPos"/>.</param> /// <param name="controlHeld">Should this selection add to the existing selection, or replace it.</param> /// <param name="ignoreSceneObjects">Optional set of objects to ignore during scene picking.</param> internal void PickObjects(Vector2I pointerPos, Vector2I area, bool controlHeld, SceneObject[] ignoreSceneObjects = null) { Internal_PickObjects(mCachedPtr, ref pointerPos, ref area, controlHeld, ignoreSceneObjects); }
/// <summary> /// Triggers when some pointing device (mouse cursor, touch) button is double clicked. /// </summary> /// <param name="screenPos">Screen position where the input event occurred.</param> /// <param name="delta">Change in movement since last sent event.</param> /// <param name="button">Button that triggered the pointer event. Might be irrelevant depending on event type. /// (for example move events don't correspond to a button.</param> /// <param name="shift">Is shift button on the keyboard being held down.</param> /// <param name="ctrl">Is control button on the keyboard being held down.</param> /// <param name="alt">Is alt button on the keyboard being held down.</param> /// <param name="scrollAmount">If mouse wheel is being scrolled, what is the amount. Only relevant for /// move events.</param> /// <param name="isUsed">Set to true if the event was handled previously by some internal system (like GUI).</param> private static void Internal_TriggerPointerDoubleClick(Vector2I screenPos, Vector2I delta, PointerButton button, bool shift, bool ctrl, bool alt, float scrollAmount, bool isUsed) { PointerEvent ev = new PointerEvent(screenPos, delta, button, shift, ctrl, alt, scrollAmount, isUsed); if (OnPointerDoubleClick != null) OnPointerDoubleClick(ev); }
/// <summary> /// Creates a new pointer event. For runtime use only. /// </summary> /// <param name="screenPos">Screen position where the input event occurred.</param> /// <param name="delta">Change in movement since last sent event.</param> /// <param name="button">Button that triggered the pointer event. Might be irrelevant depending on event type. /// (for example move events don't correspond to a button.</param> /// <param name="shift">Is shift button on the keyboard being held down.</param> /// <param name="control">Is control button on the keyboard being held down.</param> /// <param name="alt">Is alt button on the keyboard being held down.</param> /// <param name="mouseWheelScrollAmount">If mouse wheel is being scrolled, what is the amount. Only relevant for /// move events.</param> internal PointerEvent(Vector2I screenPos, Vector2I delta, PointerButton button, bool shift, bool control, bool alt, float mouseWheelScrollAmount) { _screenPos = screenPos; _delta = delta; _button = button; _shift = shift; _control = control; _alt = alt; _mouseWheelScrollAmount = mouseWheelScrollAmount; }
/// <summary> /// Returns the size of the curve editor GUI element. /// </summary> /// <returns>Width/height of the curve editor, in pixels.</returns> private Vector2I GetCurveEditorSize() { Vector2I output = new Vector2I(); output.x = Math.Max(0, Width - FIELD_DISPLAY_WIDTH - scrollBarWidth); output.y = Math.Max(0, Height - buttonLayoutHeight - scrollBarHeight); return output; }
/// <summary> /// Triggered when the user presses a mouse button. /// </summary> /// <param name="ev">Information about the mouse press event.</param> private void OnPointerPressed(PointerEvent ev) { guiCurveEditor.OnPointerPressed(ev); if (ev.button == PointerButton.Middle) { Vector2I windowPos = ScreenToWindowPos(ev.ScreenPos); Vector2 curvePos; if (guiCurveEditor.WindowToCurveSpace(windowPos, out curvePos)) { dragStartPos = windowPos; isButtonHeld = true; } } }
/// <summary> /// Attempts to find a resource tile element at the specified coordinates. /// </summary> /// <param name="scrollPos">Coordinates relative to the scroll area the content area is part of.</param> /// <returns>True if found an entry, false otherwise.</returns> public LibraryGUIEntry FindElementAt(Vector2I scrollPos) { foreach (var element in entries) { if (element.bounds.Contains(scrollPos)) return element; } return null; }
/// <summary> /// Converts coordinates in screen space to coordinates relative to the window. /// </summary> /// <param name="screenPos">Coordinates in screen space.</param> /// <returns>Coordinates relative to the window.</returns> protected Vector2I ScreenToWindowPos(Vector2I screenPos) { Vector2I windowPos; Internal_ScreenToWindowPos(mCachedPtr, ref screenPos, out windowPos); return windowPos; }
/// <summary> /// Ends the selection outline drag operation. Elements in the outline are selected. /// </summary> /// <returns>True if the selection outline drag is valid and was ended, false otherwise.</returns> private bool EndDragSelection() { if (!isDraggingSelection) return false; if (dragSelection != null) { dragSelection.Destroy(); dragSelection = null; } if ((dragSelectionEnd - dragSelectionStart).Length < 1) { isDraggingSelection = false; return false; } Vector2I min = new Vector2I(Math.Min(dragSelectionStart.x, dragSelectionEnd.x), Math.Min(dragSelectionStart.y, dragSelectionEnd.y)); Vector2I max = new Vector2I(Math.Max(dragSelectionStart.x, dragSelectionEnd.x), Math.Max(dragSelectionStart.y, dragSelectionEnd.y)); sceneSelection.PickObjects(min, max - min, Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl)); isDraggingSelection = false; return true; }
/// <summary> /// Converts coordinates relative to the window to screen space to coordinates. /// </summary> /// <param name="windowPos">Coordinates relative to the window.</param> /// <returns>Coordinates in screen space.</returns> protected Vector2I WindowToScreenPos(Vector2I windowPos) { Vector2I screenPos; Internal_WindowToScreenPos(mCachedPtr, ref windowPos, out screenPos); return screenPos; }
/// <summary> /// Converts screen coordinates into coordinates relative to the scene view render texture. /// </summary> /// <param name="screenPos">Coordinates relative to the screen.</param> /// <param name="scenePos">Output coordinates relative to the scene view texture.</param> /// <returns>True if the coordinates are within the scene view texture, false otherwise.</returns> private bool ScreenToScenePos(Vector2I screenPos, out Vector2I scenePos) { scenePos = screenPos; Vector2I windowPos = ScreenToWindowPos(screenPos); Rect2I bounds = GUIUtility.CalculateBounds(renderTextureGUI, GUI); if (bounds.Contains(windowPos)) { scenePos.x = windowPos.x - bounds.x; scenePos.y = windowPos.y - bounds.y; return true; } return false; }
private static extern void Internal_ScreenToWindowPos(IntPtr nativeInstance, ref Vector2I position, out Vector2I windowPos);
/// <summary> /// Updates a selection outline drag operation by expanding the outline to the new location. Elements in the outline /// are selected. /// </summary> /// <param name="scenePos">Coordinates of the pointer relative to the scene.</param> /// <returns>True if the selection outline drag is valid and was updated, false otherwise.</returns> private bool UpdateDragSelection(Vector2I scenePos) { if (!isDraggingSelection) return false; if (dragSelection == null) { dragSelection = new GUITexture(null, true, EditorStylesInternal.SelectionArea); selectionPanel.AddElement(dragSelection); } dragSelectionEnd = scenePos; Rect2I selectionArea = new Rect2I(); Vector2I min = new Vector2I(Math.Min(dragSelectionStart.x, dragSelectionEnd.x), Math.Min(dragSelectionStart.y, dragSelectionEnd.y)); Vector2I max = new Vector2I(Math.Max(dragSelectionStart.x, dragSelectionEnd.x), Math.Max(dragSelectionStart.y, dragSelectionEnd.y)); selectionArea.x = min.x; selectionArea.y = min.y; selectionArea.width = Math.Max(max.x - min.x, 1); selectionArea.height = Math.Max(max.y - min.y, 1); dragSelection.Bounds = selectionArea; return true; }
private static extern void Internal_CalculateOptimalSize(IntPtr element, out Vector2I output);