// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
namespace FlaxEngine.GUI
{
///
/// The checkbox control states.
///
public enum CheckBoxState
{
///
/// The default state.
///
Default,
///
/// The checked state.
///
Checked,
///
/// The intermediate state.
///
Intermediate,
}
///
/// Check box control.
///
///
public class CheckBox : Control
{
///
/// True if checked is being pressed (by mouse or touch).
///
protected bool _isPressed;
///
/// The current state.
///
protected CheckBoxState _state;
///
/// The mouse over box state.
///
protected bool _mouseOverBox;
///
/// The box size.
///
protected float _boxSize;
///
/// The box rectangle.
///
protected Rectangle _box;
///
/// Gets or sets the state of the checkbox.
///
[EditorOrder(10)]
public CheckBoxState State
{
get => _state;
set
{
if (_state != value)
{
_state = value;
StateChanged?.Invoke(this);
}
}
}
///
/// Gets or sets a value indicating whether this is checked.
///
[NoSerialize, HideInEditor]
public bool Checked
{
get => _state == CheckBoxState.Checked;
set => State = value ? CheckBoxState.Checked : CheckBoxState.Default;
}
///
/// Gets or sets a value indicating whether this is in the intermediate state.
///
[NoSerialize, HideInEditor]
public bool Intermediate
{
get => _state == CheckBoxState.Intermediate;
set => State = value ? CheckBoxState.Intermediate : CheckBoxState.Default;
}
///
/// Gets or sets the size of the box.
///
[EditorOrder(20)]
public float BoxSize
{
get => _boxSize;
set
{
_boxSize = value;
CacheBox();
}
}
///
/// Gets or sets the color of the border.
///
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
public Color BorderColor { get; set; }
///
/// Gets or sets the border color when checkbox is hovered.
///
[EditorDisplay("Border Style"), EditorOrder(2011)]
public Color BorderColorHighlighted { get; set; }
///
/// Gets or sets the color of the checkbox icon.
///
[EditorDisplay("Image Style"), EditorOrder(2020), ExpandGroups]
public Color ImageColor { get; set; }
///
/// Gets or sets the image used to render checkbox checked state.
///
[EditorDisplay("Image Style"), EditorOrder(2021), Tooltip("The image used to render checkbox checked state.")]
public IBrush CheckedImage { get; set; }
///
/// Gets or sets the image used to render checkbox intermediate state.
///
[EditorDisplay("Image Style"), EditorOrder(2022), Tooltip("The image used to render checkbox intermediate state.")]
public IBrush IntermediateImage { get; set; }
///
/// Event fired when 'checked' state gets changed.
///
public event Action StateChanged;
///
/// Initializes a new instance of the class.
///
public CheckBox()
: this(0, 0)
{
}
///
/// Initializes a new instance of the class.
///
/// The x.
/// The y.
/// if set to true set checked on start.
/// The checkbox size.
public CheckBox(float x, float y, bool isChecked = false, float size = 18)
: base(x, y, size, size)
{
_state = isChecked ? CheckBoxState.Checked : CheckBoxState.Default;
_boxSize = Mathf.Min(16.0f, size);
var style = Style.Current;
ImageColor = style.BorderSelected * 1.2f;
BorderColor = style.BorderNormal;
BorderColorHighlighted = style.BorderSelected;
CheckedImage = new SpriteBrush(style.CheckBoxTick);
IntermediateImage = new SpriteBrush(style.CheckBoxIntermediate);
CacheBox();
}
///
/// Toggles the checked state.
///
public void Toggle()
{
Checked = !Checked;
}
private void CacheBox()
{
_box = new Rectangle(0, (Height - _boxSize) * 0.5f, _boxSize, _boxSize);
}
///
/// Called when mouse or touch clicks the checkbox.
///
protected virtual void OnClick()
{
Toggle();
}
///
/// Called when checkbox starts to be pressed by the used (via mouse or touch).
///
protected virtual void OnPressBegin()
{
_isPressed = true;
if (AutoFocus)
Focus();
}
///
/// Called when checkbox ends to be pressed by the used (via mouse or touch).
///
protected virtual void OnPressEnd()
{
_isPressed = false;
}
///
public override void Draw()
{
base.Draw();
bool enabled = EnabledInHierarchy;
// Border
Color borderColor = BorderColor;
if (!enabled)
borderColor *= 0.5f;
else if (_isPressed || _mouseOverBox || IsNavFocused)
borderColor = BorderColorHighlighted;
Render2D.DrawRectangle(_box.MakeExpanded(-2.0f), borderColor);
// Icon
if (_state != CheckBoxState.Default)
{
var color = ImageColor;
if (!enabled)
color *= 0.6f;
if (_state == CheckBoxState.Checked)
CheckedImage?.Draw(_box, color);
else
IntermediateImage?.Draw(_box, color);
}
}
///
public override void OnMouseMove(Float2 location)
{
base.OnMouseMove(location);
_mouseOverBox = _box.Contains(ref location);
}
///
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && !_isPressed)
{
OnPressBegin();
return true;
}
return base.OnMouseDown(location, button);
}
///
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isPressed)
{
OnPressEnd();
if (_box.Contains(ref location))
{
OnClick();
return true;
}
}
return base.OnMouseUp(location, button);
}
///
public override void OnMouseLeave()
{
if (_isPressed)
OnPressEnd();
_mouseOverBox = false;
base.OnMouseLeave();
}
///
public override bool OnTouchDown(Float2 location, int pointerId)
{
if (!_isPressed)
{
OnPressBegin();
return true;
}
return base.OnTouchDown(location, pointerId);
}
///
public override bool OnTouchUp(Float2 location, int pointerId)
{
if (_isPressed)
{
OnPressEnd();
if (_box.Contains(ref location))
{
OnClick();
return true;
}
}
return base.OnTouchUp(location, pointerId);
}
///
public override void OnTouchLeave()
{
if (_isPressed)
OnPressEnd();
base.OnTouchLeave();
}
///
public override void OnLostFocus()
{
if (_isPressed)
OnPressEnd();
base.OnLostFocus();
}
///
protected override void OnSizeChanged()
{
base.OnSizeChanged();
CacheBox();
}
///
public override void OnSubmit()
{
OnClick();
base.OnSubmit();
}
}
}