/// /// MIT License - Copyright(c) 2019 Ugo Belfiore /// using System; using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace ExtUnityComponents { public class TinyEditorWindowSceneView { public struct SaveEditorPref { public Rect Position; public bool Minimised; } private SaveEditorPref _saveEditorPreference = new SaveEditorPref(); public string GetJsonOfSave() { _saveEditorPreference.Position = _windowMenu; _saveEditorPreference.Minimised = _isMinimised; string json = JsonUtility.ToJson(_saveEditorPreference); return (json); } public SaveEditorPref GetFromJsonDatasEditorPref(string json) { _saveEditorPreference = JsonUtility.FromJson(json); return (_saveEditorPreference); } private Rect _windowMenu; public delegate void ContentToDrawDelegate(); private ContentToDrawDelegate _methodToCall; private Event _currentEvent; private float _saveHeight = 0; private bool _isMinimised = false; private string _keyEditorPref = ""; private string _nameEditorWindow = ""; private int _id; private bool _draggable = false; public bool IsMinimisable = true; private Vector2 _lastPositionRight; private bool _snapRight; private bool _snapUp; public bool IsClosable = false; public EditorWindow _currentEditorWindow; private bool _lockToVisibleSizeX; //if true, lock to the visible screen position, else, lock to the max size of the window private bool _lockToVisibleSizeY; //if true, lock to the visible screen position, else, lock to the max size of the window private Rect _oldRect; private Vector2 _maxRect; //determine the max value of size public bool IsClosed = false; public enum DEFAULT_POSITION { NONE = 0, UP_LEFT = 10, UP = 11, UP_RIGHT = 12, MIDDLE_LEFT = 20, MIDDLE = 21, MIDDLE_RIGHT = 22, DOWN_LEFT = 30, DOWN = 31, DOWN_RIGHT = 32, } /// /// /// type: UP_LEFT UP UP_RIGHT /// anchor: (up left) (up left) (up right) /// /// type: MIDDLE_LEFT MIDDLE MIDDLE_RIGHT /// anchor: (up left) (up left) (up right) /// /// /// type: DOWN_LEFT DOWN DOWN_RIGHT /// anchor: (down left) (down left) (down right) /// /// /// /// /// public Rect GetNiceRectFromEnum(DEFAULT_POSITION position, float defaultWidth, out bool snapUp, out bool snapRight) { Rect rectNav = new Rect(0, 0, 0, 0); snapUp = true; snapRight = false; float height = 50; switch (position) { case DEFAULT_POSITION.UP_LEFT: { snapUp = true; snapRight = false; float x = 10; float y = 10; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.UP: { snapUp = true; snapRight = false; float x = (EditorGUIUtility.currentViewWidth / 2) - (defaultWidth / 2); float y = 10; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.UP_RIGHT: { snapUp = true; snapRight = true; float marginFromRight = 100f; float x = EditorGUIUtility.currentViewWidth - defaultWidth - marginFromRight; float y = 10; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.MIDDLE_LEFT: { snapUp = true; snapRight = false; float x = 10f; float y = (_currentEditorWindow.position.height / 2) - (height / 2); rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.MIDDLE_RIGHT: { snapUp = true; snapRight = true; float marginFromRight = 10f; float x = EditorGUIUtility.currentViewWidth - defaultWidth - marginFromRight; float y = (_currentEditorWindow.position.height / 2) - (height / 2); rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.DOWN_LEFT: { snapUp = false; snapRight = false; float marginFromDown = 10f; float x = 10; float y = _currentEditorWindow.position.height - height - marginFromDown; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.DOWN: { float yFromDown = 10; //from bottom, go upper float x = (EditorGUIUtility.currentViewWidth / 2) - (defaultWidth / 2); float y = SceneView.currentDrawingSceneView.camera.pixelRect.size.y - height - yFromDown; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } case DEFAULT_POSITION.DOWN_RIGHT: { float yFromDown = 10; //from bottom, go upper float xFromRight = 10; float x = EditorGUIUtility.currentViewWidth - defaultWidth - xFromRight; float y = SceneView.currentDrawingSceneView.camera.pixelRect.size.y - height - yFromDown; rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } default: case DEFAULT_POSITION.MIDDLE: { snapUp = true; snapRight = false; float x = (EditorGUIUtility.currentViewWidth / 2) - (defaultWidth / 2); float y = (_currentEditorWindow.position.height / 2) - (height / 2); rectNav = new Rect(x, y, defaultWidth, height); return (rectNav); } } } public void TinyInit(string keyEditorPref, string nameEditorWindow, DEFAULT_POSITION position, float defaultWidth = 150) { _currentEditorWindow = SceneView.currentDrawingSceneView; Rect rect = GetNiceRectFromEnum(position, defaultWidth, out bool snapUp, out bool snapRight); Init( keyEditorPref: keyEditorPref, nameEditorWindow: nameEditorWindow, id: keyEditorPref.GetHashCode(), windowMenu: rect, currentEditorWindow: _currentEditorWindow, currentEvent: Event.current, draggable: true, isMinimisable: false, snapRight: snapRight, snapUp: snapUp, maxRect: new Vector2(0, 0), applySetup: true, closable: true, lockToVisibleSizeX: true, lockToVisibleSizeY: true); } /// /// need to be called in OnGUI /// public void Init(string keyEditorPref, string nameEditorWindow, int id, Rect windowMenu, EditorWindow currentEditorWindow, Event currentEvent, bool draggable, bool isMinimisable, bool snapRight, bool snapUp, Vector2 maxRect, bool applySetup = true, bool closable = false, bool lockToVisibleSizeX = true, bool lockToVisibleSizeY = true) { _maxRect = maxRect; _lockToVisibleSizeX = lockToVisibleSizeX; _lockToVisibleSizeY = lockToVisibleSizeY; _keyEditorPref = keyEditorPref; _nameEditorWindow = nameEditorWindow; _id = id; _windowMenu = windowMenu; _currentEditorWindow = currentEditorWindow; _currentEvent = currentEvent; _draggable = draggable; IsMinimisable = isMinimisable; _snapRight = snapRight; _snapUp = snapUp; _isMinimised = false; _saveHeight = _windowMenu.height; IsClosable = closable; IsClosed = false; if (applySetup) { ApplySetup(); } } public void SetNewPosition(Vector2 newPosition, Event currentEvent) { _currentEvent = currentEvent; _windowMenu.x = newPosition.x; _windowMenu.y = newPosition.y; EditorPrefs.SetString(_keyEditorPref, GetJsonOfSave()); } public Rect GetPosition() { return (_windowMenu); } private void ApplySetup() { if (!string.IsNullOrEmpty(_keyEditorPref) && EditorPrefs.HasKey(_keyEditorPref)) { ApplySaveSettings(); } SavePositionFromRight(_snapRight, _snapUp); } /// /// apply the settings of the saved EditorPref /// private void ApplySaveSettings() { string keyRect = EditorPrefs.GetString(_keyEditorPref); _saveEditorPreference = GetFromJsonDatasEditorPref(keyRect); _windowMenu = new Rect(_saveEditorPreference.Position.x, _saveEditorPreference.Position.y, _windowMenu.width, _windowMenu.height); _isMinimised = _saveEditorPreference.Minimised; if (!IsMinimisable) { IsMinimisable = false; } } private bool HasChanged() { if (_saveEditorPreference.Position != _windowMenu || _saveEditorPreference.Minimised != _isMinimised) { return (true); } return (false); } private void SavePositionFromRight(bool snapRight, bool snapUp) { if (_currentEditorWindow == null) { _lastPositionRight = new Vector2(_windowMenu.x, _windowMenu.y); return; } float SnapWidth = (_lockToVisibleSizeX) ? EditorGUIUtility.currentViewWidth : _currentEditorWindow.position.height; float Snapheight = (_lockToVisibleSizeY) ? _currentEditorWindow.position.height : _currentEditorWindow.maxSize.y; _lastPositionRight.x = (snapRight) ? SnapWidth - _windowMenu.x : _windowMenu.x; _lastPositionRight.y = (snapUp) ? _windowMenu.y : Snapheight - _windowMenu.y; } private Vector2 GetNewRightPositiionFromOld(bool snapXRight, bool snapYUp) { if (_currentEditorWindow == null) { return (_lastPositionRight); } float SnapWidth = (_lockToVisibleSizeX) ? EditorGUIUtility.currentViewWidth : _currentEditorWindow.position.height; float Snapheight = (_lockToVisibleSizeY) ? _currentEditorWindow.position.height : _currentEditorWindow.maxSize.y; Vector2 pos; pos.x = (snapXRight) ? SnapWidth - _lastPositionRight.x : _lastPositionRight.x; pos.y = (snapYUp) ? _lastPositionRight.y : Snapheight - _lastPositionRight.y; return (pos); } /// /// called every frame, /// /// public Rect ShowEditorWindow(ContentToDrawDelegate action, EditorWindow currentEditorWindow, Event current) { _methodToCall = action; _currentEvent = current; _currentEditorWindow = currentEditorWindow; _windowMenu = ReworkPosition(_windowMenu, _snapRight, _snapUp); if (!IsMinimisable) { _isMinimised = false; } if (_isMinimised) { _windowMenu.height = 15f; _windowMenu = GUI.Window(_id, _windowMenu, NavigatorWindow, _nameEditorWindow); SavePositionFromRight(_snapRight, _snapUp); } else { //here resize auto _windowMenu = GUILayout.Window(_id, _windowMenu, NavigatorWindow, _nameEditorWindow, GUILayout.ExpandHeight(true)); SavePositionFromRight(_snapRight, _snapUp); } if (!string.IsNullOrEmpty(_keyEditorPref) && HasChanged()) { EditorPrefs.SetString(_keyEditorPref, GetJsonOfSave()); } return (_windowMenu); } /// /// /// /// /// public void SetMinimise(bool minimise, bool hard) { if (!IsMinimisable) { if (!hard) { return; } _isMinimised = minimise; } _isMinimised = minimise; } private void DisplayClosable() { float x = _windowMenu.width - 20; float y = 0; float width = 20f; float height = 15f; if (_maxRect.x > 0) { x = Mathf.Min(_maxRect.x, x); } if (_maxRect.y > 0) { y = Mathf.Min(_maxRect.y, y); } GUILayout.BeginArea(new Rect(x, y, width, height)); if (GUILayout.Button(" x ")) { IsClosed = true; } GUILayout.EndArea(); } /// /// called to display the minimsie button /// private void DisplayMinimise() { if (_isMinimised) { GUILayout.BeginArea(new Rect(0, 0, _windowMenu.width, 15)); GUILayout.Label(" " + _nameEditorWindow); GUILayout.EndArea(); } float x = _windowMenu.width - 20; float y = 0; float width = 20f; float height = 15f; GUILayout.BeginArea(new Rect(x, y, width, height)); bool minimise = GUILayout.Button(" - "); GUILayout.EndArea(); if (minimise) { _isMinimised = (_isMinimised) ? false : true; } } private void DisplayDraggable() { GUILayout.BeginArea(new Rect(0, 0, 15, 15)); GUILayout.Label("#"); GUILayout.EndArea(); } /// /// give restriction to position of the panel /// /// /// private Rect ReworkPosition(Rect currentPosition, bool snapRight, bool snapUp) { if (_currentEditorWindow == null) { return (currentPosition); } if (_maxRect.x > 0) { currentPosition.width = Mathf.Min(_maxRect.x, currentPosition.width); } if (_maxRect.y > 0) { currentPosition.height = Mathf.Min(_maxRect.y, currentPosition.height); } Vector2 snapToRight = GetNewRightPositiionFromOld(snapRight, snapUp); currentPosition.x = snapToRight.x; currentPosition.y = snapToRight.y; float minX = 10; float minY = 20; float maxX = EditorGUIUtility.currentViewWidth - currentPosition.width - minX; float maxY = _currentEditorWindow.position.height - currentPosition.height - 5; if (!_lockToVisibleSizeX) { maxX = _currentEditorWindow.maxSize.x - currentPosition.width - minX; } if (!_lockToVisibleSizeY) { maxY = _currentEditorWindow.maxSize.y - currentPosition.height - 5; } if (currentPosition.x < minX) { currentPosition.x = minX; _snapRight = false; } if (currentPosition.x > maxX) { currentPosition.x = maxX; _snapRight = true; } if (currentPosition.y < minY) { currentPosition.y = minY; _snapUp = true; } //here the _sceneView.camera.pixelRect.size.y is incoherent when applying this event if (_currentEvent.type == EventType.Repaint) { //Debug.Log(_currentEvent.type); if (currentPosition.y > maxY) { currentPosition.y = maxY; _snapUp = false; } } return (currentPosition); } /// /// draw the editor window with everything in it /// /// private void NavigatorWindow(int id) { if (IsClosable) { DisplayClosable(); } else if (IsMinimisable) { DisplayMinimise(); } if (_draggable) { DisplayDraggable(); GUI.DragWindow(new Rect(0, 0, _windowMenu.width - 20, 20)); //allow to drag de window only at the top } //don't draw anything if it's minimised if (_isMinimised) { return; } _methodToCall(); PreventClicGoThought(Event.current); } public void PreventClicGoThought(Event current) { if ((current.type == EventType.MouseDrag || current.type == EventType.MouseDown) && current.button == 0) { Event.current.Use(); } } } }