// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.GUI.Input { /// /// Base class for text boxes for float/int value editing. Supports slider and range clamping. /// /// The value type. /// [HideInEditor] public abstract class ValueBox : TextBox where T : struct, IComparable { /// /// The sliding box size. /// protected const float SlidingBoxSize = 12.0f; /// /// The current value. /// protected T _value; /// /// The minimum value. /// protected T _min; /// /// The maximum value. /// protected T _max; /// /// The slider speed. /// protected float _slideSpeed; /// /// True if slider is in use. /// protected bool _isSliding; /// /// The value cached on sliding start. /// protected T _startSlideValue; private Vector2 _startSlideLocation; /// /// Occurs when value gets changed. /// public event Action ValueChanged; /// /// Occurs when value gets changed. /// public event Action> BoxValueChanged; /// /// Gets or sets the value. /// public abstract T Value { get; set; } /// /// Gets or sets the minimum value. /// public abstract T MinValue { get; set; } /// /// Gets or sets the maximum value. /// public abstract T MaxValue { get; set; } /// /// Gets a value indicating whether user is using a slider. /// public bool IsSliding => _isSliding; /// /// Occurs when sliding starts. /// public event Action SlidingStart; /// /// Occurs when sliding ends. /// public event Action SlidingEnd; /// /// Gets or sets the slider speed. Use value 0 to disable and hide slider UI. /// public float SlideSpeed { get => _slideSpeed; set => _slideSpeed = value; } /// /// Initializes a new instance of the class. /// /// The value. /// The x. /// The y. /// The width. /// The minimum. /// The maximum. /// The slider speed. protected ValueBox(T value, float x, float y, float width, T min, T max, float sliderSpeed) : base(false, x, y, width) { _value = value; _min = min; _max = max; _slideSpeed = sliderSpeed; } /// /// Updates the text of the textbox. /// protected abstract void UpdateText(); /// /// Tries the get value from the textbox text. /// protected abstract void TryGetValue(); /// /// Applies the sliding delta to the value. /// /// The delta (scaled). protected abstract void ApplySliding(float delta); /// /// Called when value gets changed. /// protected virtual void OnValueChanged() { ValueChanged?.Invoke(); BoxValueChanged?.Invoke(this); } /// /// Gets a value indicating whether this value box can use sliding. /// protected virtual bool CanUseSliding => _slideSpeed > Mathf.Epsilon; /// /// Gets the slide rectangle. /// protected virtual Rectangle SlideRect { get { float x = Width - SlidingBoxSize - 1.0f; float y = (Height - SlidingBoxSize) * 0.5f; return new Rectangle(x, y, SlidingBoxSize, SlidingBoxSize); } } private void EndSliding() { _isSliding = false; EndMouseCapture(); SlidingEnd?.Invoke(); } /// public override void Draw() { base.Draw(); if (CanUseSliding) { var style = Style.Current; // Draw sliding UI Render2D.DrawSprite(style.Scale, SlideRect, style.Foreground); // Check if is sliding if (_isSliding) { // Draw overlay // TODO: render nicer overlay with some glow from the borders (inside) Render2D.FillRectangle(new Rectangle(Vector2.Zero, Size), Color.Orange * 0.3f); } } } /// public override void OnLostFocus() { // Check if was sliding if (_isSliding) { EndSliding(); base.OnLostFocus(); } else { base.OnLostFocus(); // Update UpdateText(); } ResetViewOffset(); } /// public override bool OnMouseDown(Vector2 location, MouseButton button) { if (button == MouseButton.Left && CanUseSliding && SlideRect.Contains(location)) { // Start sliding _isSliding = true; _startSlideLocation = location; _startSlideValue = _value; StartMouseCapture(true); SlidingStart?.Invoke(); return true; } return base.OnMouseDown(location, button); } /// public override void OnMouseMove(Vector2 location) { if (_isSliding) { // Update sliding Vector2 slideLocation = location + Root.TrackingMouseOffset; ApplySliding(Mathf.RoundToInt(slideLocation.X - _startSlideLocation.X) * _slideSpeed); } else { base.OnMouseMove(location); } } /// public override bool OnMouseUp(Vector2 location, MouseButton button) { if (button == MouseButton.Left && _isSliding) { // End sliding EndSliding(); return true; } return base.OnMouseUp(location, button); } /// protected override void OnEditEnd() { // Update value TryGetValue(); base.OnEditEnd(); } /// public override void OnEndMouseCapture() { // Check if was sliding if (_isSliding) { EndSliding(); } else { base.OnEndMouseCapture(); } } /// protected override Rectangle TextRectangle { get { var result = base.TextRectangle; if (CanUseSliding) { result.Size.X -= SlidingBoxSize; } return result; } } /// protected override Rectangle TextClipRectangle { get { var result = base.TextRectangle; if (CanUseSliding) { result.Size.X -= SlidingBoxSize; } return result; } } } }