Files
FlaxEngine/Source/Editor/GUI/Popups/RenamePopup.cs

211 lines
6.4 KiB
C#

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
/// <summary>
/// Popup menu useful for renaming objects via UI. Displays text box for renaming.
/// </summary>
/// <seealso cref="ContextMenuBase" />
public class RenamePopup : ContextMenuBase
{
private string _startValue;
private TextBox _inputField;
/// <summary>
/// Occurs when renaming is done.
/// </summary>
public event Action<RenamePopup> Renamed;
/// <summary>
/// Occurs when popup is closing (after renaming done or not).
/// </summary>
public event Action<RenamePopup> Closed;
/// <summary>
/// Input value validation delegate.
/// </summary>
/// <param name="popup">The popup reference.</param>
/// <param name="value">The input text value.</param>
/// <returns>True if text is valid, otherwise false.</returns>
public delegate bool ValidateDelegate(RenamePopup popup, string value);
/// <summary>
/// Occurs when input text validation should be performed.
/// </summary>
public ValidateDelegate Validate;
/// <summary>
/// Gets or sets the initial value.
/// </summary>
public string InitialValue
{
get => _startValue;
set => _startValue = value;
}
/// <summary>
/// Gets or sets the input field text.
/// </summary>
public string Text
{
get => _inputField.Text;
set => _inputField.Text = value;
}
/// <summary>
/// Gets the text input field control.
/// </summary>
public TextBox InputField => _inputField;
/// <summary>
/// Initializes a new instance of the <see cref="RenamePopup"/> class.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="size">The size.</param>
/// <param name="isMultiline">Enable/disable multiline text input support</param>
public RenamePopup(string value, Float2 size, bool isMultiline)
{
if (!isMultiline)
size.Y = TextBox.DefaultHeight;
Size = size;
_startValue = value;
_inputField = new TextBox(isMultiline, 0, 0, size.Y);
_inputField.TextChanged += OnTextChanged;
_inputField.AnchorPreset = AnchorPresets.StretchAll;
_inputField.Offsets = Margin.Zero;
_inputField.Text = _startValue;
_inputField.Parent = this;
}
private bool IsInputValid => !string.IsNullOrWhiteSpace(_inputField.Text) && (_inputField.Text == _startValue || Validate == null || Validate(this, _inputField.Text));
/// <inheritdoc />
public override void Update(float deltaTime)
{
var mouseLocation = Root.MousePosition;
if (!ContainsPoint(ref mouseLocation) && RootWindow.ContainsFocus && Text != _startValue)
{
// rename item before closing if left mouse button in clicked
if (FlaxEngine.Input.GetMouseButtonDown(MouseButton.Left))
OnEnd();
}
base.Update(deltaTime);
}
private void OnTextChanged()
{
if (Validate == null)
return;
var valid = IsInputValid;
var style = Style.Current;
if (valid)
{
_inputField.BorderColor = Color.Transparent;
_inputField.BorderSelectedColor = style.BackgroundSelected;
}
else
{
var color = new Color(1.0f, 0.0f, 0.02745f, 1.0f);
_inputField.BorderColor = Color.Lerp(color, style.TextBoxBackground, 0.6f);
_inputField.BorderSelectedColor = color;
}
}
/// <summary>
/// Shows the rename popup.
/// </summary>
/// <param name="control">The target control.</param>
/// <param name="area">The target control area to cover.</param>
/// <param name="value">The initial value.</param>
/// <param name="isMultiline">Enable/disable multiline text input support</param>
/// <returns>Created popup.</returns>
public static RenamePopup Show(Control control, Rectangle area, string value, bool isMultiline)
{
// Calculate the control size in the window space to handle scaled controls
var upperLeft = control.PointToWindow(area.UpperLeft);
var bottomRight = control.PointToWindow(area.BottomRight);
var size = bottomRight - upperLeft;
var rename = new RenamePopup(value, size, isMultiline);
rename.Show(control, area.Location + new Float2(0, (size.Y - rename.Height) * 0.5f));
return rename;
}
private void OnEnd()
{
var text = Text;
if (text != _startValue && IsInputValid)
{
Renamed?.Invoke(this);
}
Hide();
}
/// <inheritdoc />
protected override bool UseAutomaticDirectionFix => false;
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
// Enter
if (key == KeyboardKeys.Return)
{
OnEnd();
return true;
}
// Esc
if (key == KeyboardKeys.Escape)
{
Hide();
return true;
}
// Base
return base.OnKeyDown(key);
}
/// <inheritdoc />
protected override void OnShow()
{
_inputField.EndEditOnClick = false; // Ending edit is handled through popup
_inputField.Focus();
_inputField.SelectAll();
base.OnShow();
}
/// <inheritdoc />
protected override void OnHide()
{
Closed?.Invoke(this);
Closed = null;
base.OnHide();
// Remove itself
Dispose();
}
/// <inheritdoc />
public override void OnDestroy()
{
Renamed = null;
Closed = null;
Validate = null;
_inputField = null;
base.OnDestroy();
}
}
}