Created
August 11, 2017 15:20
-
-
Save kirevdokimov/49bac51825c9967f4df7ba9258d8882b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor; | |
using UnityEngine; | |
//http://answers.unity3d.com/questions/463207/how-do-you-make-a-custom-handle-respond-to-the-mou.html | |
// Author http://answers.unity3d.com/users/57609/higekun.html | |
public class MyHandles{ | |
public enum DragHandleResult{ | |
none = 0, | |
LMBPress, | |
LMBClick, | |
LMBDoubleClick, | |
LMBDrag, | |
LMBRelease, | |
RMBPress, | |
RMBClick, | |
RMBDoubleClick, | |
RMBDrag, | |
RMBRelease | |
} | |
// Храним хеш строки DragHandleHash в качестве индивидуального ключа | |
private static readonly int s_DragHandleHash = "DragHandleHash".GetHashCode(); | |
private static Vector2 s_DragHandleMouseStart; | |
private static Vector2 s_DragHandleMouseCurrent; | |
private static Vector3 s_DragHandleWorldStart; | |
private static float s_DragHandleClickTime; | |
private static int s_DragHandleClickID; | |
private static readonly float s_DragHandleDoubleClickInterval = 0.5f; // допустимый интервал между кликами, чтобы сработал doubleClick | |
private static bool s_DragHandleHasMoved; | |
// externally accessible to get the ID of the most resently processed DragHandle | |
public static int lastDragHandleID; | |
// | |
public static Vector3 DragHandle(Vector3 position, float handleSize, Handles.CapFunction capFunc, Color colorSelected, | |
out DragHandleResult result){ | |
// Используем хеш ключ для получения индивидуального ключа контроля | |
var id = GUIUtility.GetControlID(s_DragHandleHash, FocusType.Passive); | |
// Переменная для хранения id, доступная извне (public) | |
lastDragHandleID = id; | |
//???// | |
var screenPosition = Handles.matrix.MultiplyPoint(position); | |
// Сохраняем действующую матрицу в отдельную переменную, чтобы после отработки всего кода вернуть Handles матрицу в прежнее состояние | |
var cachedMatrix = Handles.matrix; | |
result = DragHandleResult.none; | |
// Проверяем на события | |
switch(Event.current.GetTypeForControl(id)){ | |
// Мышь нажата | |
case EventType.MouseDown: | |
/* | |
HandleUtility.nearestControl по видимому возвращает id ближайшего контроллера | |
public static int nearestControl{ | |
get { return (double) HandleUtility.s_NearestDistance > 5.0 ? 0 : HandleUtility.s_NearestControl;} | |
set { HandleUtility.s_NearestControl = value; } | |
} | |
public static void AddControl(int controlId, float distance){ | |
if ((double) distance < (double) HandleUtility.s_CustomPickDistance && (double) distance > 5.0) | |
distance = 5f; | |
if ((double) distance > (double) HandleUtility.s_NearestDistance) | |
return; | |
HandleUtility.s_NearestDistance = distance; | |
HandleUtility.s_NearestControl = controlId; <<< ! | |
} | |
--- | |
Event.current.button == 0 < left mouse button click | |
Event.current.button == 1 < right mouse button click | |
*/ | |
if(HandleUtility.nearestControl == id && (Event.current.button == 0 || Event.current.button == 1)){ | |
/* | |
Записывая текущий контроллер как hot мы позволяем только ему перехватывать события мыши | |
*/ | |
GUIUtility.hotControl = id; | |
s_DragHandleMouseCurrent = s_DragHandleMouseStart = Event.current.mousePosition; | |
s_DragHandleWorldStart = position; | |
s_DragHandleHasMoved = false; | |
// использование Use позволяет как бы обнулить событие, что непозволит другим элементам среагировать на него | |
// http://answers.unity3d.com/questions/971262/when-to-actually-use-eventuse.html | |
Event.current.Use(); | |
/* Когда ведешь контроллер к краю экрана эта строчка позволяет курсору мыши перескочить на другой край и продолжать двигаться | |
Типа как если взять rotation tool и двигать мышь постоянно влево | |
*/ | |
EditorGUIUtility.SetWantsMouseJumping(1); | |
// Записываем состояние коонтроллера в DragHandleResult | |
if(Event.current.button == 0) | |
result = DragHandleResult.LMBPress; | |
else if(Event.current.button == 1) | |
result = DragHandleResult.RMBPress; | |
} | |
break; | |
// Мышь отпущена | |
case EventType.MouseUp: | |
if(GUIUtility.hotControl == id && (Event.current.button == 0 || Event.current.button == 1)){ | |
// Отключаем горячесть контроллера | |
GUIUtility.hotControl = 0; | |
Event.current.Use(); | |
// Отключаем фичу с перескоками | |
EditorGUIUtility.SetWantsMouseJumping(0); | |
if(Event.current.button == 0) | |
result = DragHandleResult.LMBRelease; | |
else if(Event.current.button == 1) | |
result = DragHandleResult.RMBRelease; | |
// Мышь не сдвинулась | |
if(Event.current.mousePosition == s_DragHandleMouseStart){ | |
// Если текущий id клика идентичный предыдущему и интервал между кликами не высок то doubleClick = true; | |
var doubleClick = s_DragHandleClickID == id && | |
Time.realtimeSinceStartup - s_DragHandleClickTime < s_DragHandleDoubleClickInterval; | |
s_DragHandleClickID = id; // Храним id клика | |
s_DragHandleClickTime = Time.realtimeSinceStartup; // Храним время клика | |
if(Event.current.button == 0) | |
result = doubleClick ? DragHandleResult.LMBDoubleClick : DragHandleResult.LMBClick; | |
else if(Event.current.button == 1) | |
result = doubleClick ? DragHandleResult.RMBDoubleClick : DragHandleResult.RMBClick; | |
} | |
} | |
break; | |
case EventType.MouseDrag: | |
// Если текущий контроллер активен | |
if(GUIUtility.hotControl == id){ | |
// Рассчет новойц позиции мыши | |
s_DragHandleMouseCurrent += new Vector2(Event.current.delta.x, -Event.current.delta.y); | |
//???// Handles.matrix.MultiplyPoint | |
// Рассчет текущего смещения мыши относительно s_DragHandleMouseStart | |
var position2 = Camera.current.WorldToScreenPoint(Handles.matrix.MultiplyPoint(s_DragHandleWorldStart)) | |
+ (Vector3) (s_DragHandleMouseCurrent - s_DragHandleMouseStart); | |
// Перевод в мировые координаты | |
position = Handles.matrix.inverse.MultiplyPoint(Camera.current.ScreenToWorldPoint(position2)); | |
// Если камера смотрит ровно по направлению Vector3.forward или - Vector3.forward | |
if(Camera.current.transform.forward == Vector3.forward || Camera.current.transform.forward == -Vector3.forward) | |
position.z = s_DragHandleWorldStart.z; // То не изменяем позицию по z | |
// Такая же система | |
if(Camera.current.transform.forward == Vector3.up || Camera.current.transform.forward == -Vector3.up) | |
position.y = s_DragHandleWorldStart.y; | |
if(Camera.current.transform.forward == Vector3.right || Camera.current.transform.forward == -Vector3.right) | |
position.x = s_DragHandleWorldStart.x; | |
if(Event.current.button == 0) | |
result = DragHandleResult.LMBDrag; | |
else if(Event.current.button == 1) | |
result = DragHandleResult.RMBDrag; | |
s_DragHandleHasMoved = true; | |
// Сообщаем GUI, что контроллер изменил состояние входных данных | |
GUI.changed = true; | |
Event.current.Use(); | |
} | |
break; | |
case EventType.Repaint: | |
var currentColour = Handles.color; | |
if(id == GUIUtility.hotControl && s_DragHandleHasMoved) | |
Handles.color = colorSelected; | |
Handles.matrix = Matrix4x4.identity; | |
capFunc(id, screenPosition, Quaternion.identity, handleSize, EventType.Repaint); | |
Handles.matrix = cachedMatrix; | |
Handles.color = currentColour; | |
break; | |
case EventType.Layout: | |
Handles.matrix = Matrix4x4.identity; | |
// Добавление контроллера | |
// Тут не берется во внимание какой cap стоит и тут всегда дистанция считается через DistanceToCircle | |
// Вообще такие дела с id и AddControl делаются в CapFunction | |
//HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(screenPosition, handleSize)); | |
capFunc(id, screenPosition, Quaternion.identity, handleSize, EventType.Layout); | |
Handles.matrix = cachedMatrix; | |
break; | |
} | |
return position; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment