// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI
{
///
/// Popup menu useful for renaming objects via UI. Displays text box for renaming.
///
///
public class RenamePopup : ContextMenuBase
{
private string _startValue;
private TextBox _inputField;
///
/// Occurs when renaming is done.
///
public event Action Renamed;
///
/// Occurs when popup is closing (after renaming done or not).
///
public event Action Closed;
///
/// Input value validation delegate.
///
/// The popup reference.
/// The input text value.
/// True if text is valid, otherwise false.
public delegate bool ValidateDelegate(RenamePopup popup, string value);
///
/// Occurs when input text validation should be performed.
///
public ValidateDelegate Validate;
///
/// Gets or sets the initial value.
///
public string InitialValue
{
get => _startValue;
set => _startValue = value;
}
///
/// Gets or sets the input field text.
///
public string Text
{
get => _inputField.Text;
set => _inputField.Text = value;
}
///
/// Gets the text input field control.
///
public TextBox InputField => _inputField;
///
/// Initializes a new instance of the class.
///
/// The value.
/// The size.
/// Enable/disable multiline text input support
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));
///
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;
}
}
///
/// Shows the rename popup.
///
/// The target control.
/// The target control area to cover.
/// The initial value.
/// Enable/disable multiline text input support
/// Created popup.
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();
}
///
protected override bool UseAutomaticDirectionFix => false;
///
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);
}
///
protected override void OnShow()
{
_inputField.EndEditOnClick = false; // Ending edit is handled through popup
_inputField.Focus();
_inputField.SelectAll();
base.OnShow();
}
///
protected override void OnHide()
{
Closed?.Invoke(this);
Closed = null;
base.OnHide();
// Remove itself
Dispose();
}
///
public override void OnDestroy()
{
Renamed = null;
Closed = null;
Validate = null;
_inputField = null;
base.OnDestroy();
}
}
}