diff options
author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Export/SliderHandler.cs |
Diffstat (limited to 'Runtime/Export/SliderHandler.cs')
-rw-r--r-- | Runtime/Export/SliderHandler.cs | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/Runtime/Export/SliderHandler.cs b/Runtime/Export/SliderHandler.cs new file mode 100644 index 0000000..057ef70 --- /dev/null +++ b/Runtime/Export/SliderHandler.cs @@ -0,0 +1,330 @@ +using System; + +namespace UnityEngine +{ + // State for when we're dragging a slider. + internal class SliderState + { + public float dragStartPos; + public float dragStartValue; + public bool isDragging; + } + + // TODO: Make the thumb positioning / sizing be right + internal struct SliderHandler + { + readonly Rect position; + readonly float currentValue; + readonly float size; + readonly float start; + readonly float end; + readonly GUIStyle slider; + readonly GUIStyle thumb; + readonly bool horiz; + readonly int id; + + public SliderHandler(Rect position, float currentValue, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id) + { + this.position = position; + this.currentValue = currentValue; + this.size = size; + this.start = start; + this.end = end; + this.slider = slider; + this.thumb = thumb; + this.horiz = horiz; + this.id = id; + } + + public float Handle() + { + if (slider == null || thumb == null) + return currentValue; + + switch (CurrentEventType()) + { + case EventType.MouseDown: + return OnMouseDown(); + + case EventType.MouseDrag: + return OnMouseDrag(); + + case EventType.MouseUp: + return OnMouseUp(); + + case EventType.Repaint: + return OnRepaint(); + } + return currentValue; + } + + private float OnMouseDown() + { + // if the click is outside this control, just bail out... + if (!position.Contains(CurrentEvent().mousePosition) || IsEmptySlider()) + return currentValue; + + GUI.scrollTroughSide = 0; + GUIUtility.hotControl = id; + CurrentEvent().Use(); + + if (ThumbSelectionRect().Contains(CurrentEvent().mousePosition)) + { + // We have a mousedown on the thumb + // Record where we're draging from, so the user can get back. + StartDraggingWithValue(ClampedCurrentValue()); + return currentValue; + } + + GUI.changed = true; + + // We're outside the thumb, but inside the trough. + // If we have a scrollSize, we do pgup/pgdn style movements + // if not, we just snap to the current position and begin tracking + if (SupportsPageMovements()) + { + SliderState().isDragging = false; + GUI.nextScrollStepTime = SystemClock.now.AddMilliseconds(ScrollWaitDefinitions.firstWait); + GUI.scrollTroughSide = CurrentScrollTroughSide(); + return PageMovementValue(); + } + + float newValue = ValueForCurrentMousePosition(); + StartDraggingWithValue(newValue); + return Clamp(newValue); + } + + private float OnMouseDrag() + { + if (GUIUtility.hotControl != id) + return currentValue; + + var sliderState = SliderState(); + if (!sliderState.isDragging) + return currentValue; + + GUI.changed = true; + CurrentEvent().Use(); + + // Recalculate the value from the mouse position. this has the side effect that values are relative to the + // click point - no matter where inside the trough the original value was. Also means user can get back original value + // if he drags back to start position. + float deltaPos = MousePosition() - sliderState.dragStartPos; + var newValue = sliderState.dragStartValue + deltaPos / ValuesPerPixel(); + return Clamp(newValue); + } + + private float OnMouseUp() + { + if (GUIUtility.hotControl == id) + { + CurrentEvent().Use(); + GUIUtility.hotControl = 0; + } + return currentValue; + } + + private float OnRepaint() + { + slider.Draw(position, GUIContent.none, id); + thumb.Draw(ThumbRect(), GUIContent.none, id); + + if (GUIUtility.hotControl != id || !position.Contains(CurrentEvent().mousePosition) || IsEmptySlider()) + return currentValue; + + if (ThumbRect().Contains(CurrentEvent().mousePosition)) + { + if (GUI.scrollTroughSide != 0) // if was scrolling with "trough" and the thumb reached mouse - sliding action over + { + GUIUtility.hotControl = 0; + } + + return currentValue; + } + + GUI.InternalRepaintEditorWindow(); + + if (SystemClock.now < GUI.nextScrollStepTime) + return currentValue; + + if (CurrentScrollTroughSide() != GUI.scrollTroughSide) + return currentValue; + + GUI.nextScrollStepTime = SystemClock.now.AddMilliseconds(ScrollWaitDefinitions.regularWait); + + if (SupportsPageMovements()) + { + SliderState().isDragging = false; + GUI.changed = true; + return PageMovementValue(); + } + return ClampedCurrentValue(); + } + + private EventType CurrentEventType() + { + return CurrentEvent().GetTypeForControl(id); + } + + private int CurrentScrollTroughSide() + { + float mousePos = horiz ? CurrentEvent().mousePosition.x : CurrentEvent().mousePosition.y; + float thumbPos = horiz ? ThumbRect().x : ThumbRect().y; + + return mousePos > thumbPos ? 1 : -1; + } + + private bool IsEmptySlider() + { + return start == end; + } + + private bool SupportsPageMovements() + { + return size != 0 && GUI.usePageScrollbars; + } + + private float PageMovementValue() + { + var newValue = currentValue; + var sign = start > end ? -1 : 1; + if (MousePosition() > PageUpMovementBound()) + newValue += size * sign * .9f; + else + newValue -= size * sign * .9f; + return Clamp(newValue); + } + + private float PageUpMovementBound() + { + if (horiz) + return ThumbRect().xMax - position.x; + return ThumbRect().yMax - position.y; + } + + private Event CurrentEvent() + { + return Event.current; + } + + private float ValueForCurrentMousePosition() + { + if (horiz) + return (MousePosition() - ThumbRect().width * .5f) / ValuesPerPixel() + start - size * .5f; + return (MousePosition() - ThumbRect().height * .5f) / ValuesPerPixel() + start - size * .5f; + } + + private float Clamp(float value) + { + return Mathf.Clamp(value, MinValue(), MaxValue()); + } + + private Rect ThumbSelectionRect() + { + var selectionRect = ThumbRect(); +#if UNITY_IPHONE + int minSize = 12; + if (selectionRect.width < minSize) + { + selectionRect.x -= (minSize - selectionRect.width) / 2; + selectionRect.width = minSize; + } + if (selectionRect.height < minSize) + { + selectionRect.y -= (minSize - selectionRect.height) / 2; + selectionRect.height = minSize; + } + +#endif + return selectionRect; + } + + private void StartDraggingWithValue(float dragStartValue) + { + var state = SliderState(); + state.dragStartPos = MousePosition(); + state.dragStartValue = dragStartValue; + state.isDragging = true; + } + + private SliderState SliderState() + { + return (SliderState)GUIUtility.GetStateObject(typeof(SliderState), id); + } + + private Rect ThumbRect() + { + return horiz ? HorizontalThumbRect() : VerticalThumbRect(); + } + + private Rect VerticalThumbRect() + { + var valuesPerPixel = ValuesPerPixel(); + if (start < end) + return new Rect( + position.x + slider.padding.left, + (ClampedCurrentValue() - start) * valuesPerPixel + position.y + slider.padding.top, + position.width - slider.padding.horizontal, + size * valuesPerPixel + ThumbSize()); + + return new Rect( + position.x + slider.padding.left, + (ClampedCurrentValue() + size - start) * valuesPerPixel + position.y + slider.padding.top, + position.width - slider.padding.horizontal, + size * -valuesPerPixel + ThumbSize()); + } + + private Rect HorizontalThumbRect() + { + var valuesPerPixel = ValuesPerPixel(); + if (start < end) + return new Rect( + (ClampedCurrentValue() - start) * valuesPerPixel + position.x + slider.padding.left, + position.y + slider.padding.top, + size * valuesPerPixel + ThumbSize(), + position.height - slider.padding.vertical); + + return new Rect( + (ClampedCurrentValue() + size - start) * valuesPerPixel + position.x + slider.padding.left, + position.y, + size * -valuesPerPixel + ThumbSize(), + position.height); + } + + private float ClampedCurrentValue() + { + return Clamp(currentValue); + } + + private float MousePosition() + { + if (horiz) + return CurrentEvent().mousePosition.x - position.x; + return CurrentEvent().mousePosition.y - position.y; + } + + private float ValuesPerPixel() + { + if (horiz) + return (position.width - slider.padding.horizontal - ThumbSize()) / (end - start); + return (position.height - slider.padding.vertical - ThumbSize()) / (end - start); + } + + private float ThumbSize() + { + if (horiz) + return thumb.fixedWidth != 0 ? thumb.fixedWidth : thumb.padding.horizontal; + return thumb.fixedHeight != 0 ? thumb.fixedHeight : thumb.padding.vertical; + } + + private float MaxValue() + { + return Mathf.Max(start, end) - size; + } + + private float MinValue() + { + return Mathf.Min(start, end); + } + } +} |