Refactor Editor Tab controls system to allows customizing the tab header controls

This commit is contained in:
Wojtek Figat
2023-09-12 22:24:15 +02:00
parent 3e1940c799
commit dbd85fddfe
2 changed files with 81 additions and 40 deletions

View File

@@ -77,5 +77,14 @@ namespace FlaxEditor.GUI.Tabs
{
Deselected?.Invoke(this);
}
/// <summary>
/// Factory method for tabs header control (UI for the tabs strip to represent this tab).
/// </summary>
/// <returns>The tab header control.</returns>
public virtual Tabs.TabHeader CreateHeader()
{
return new Tabs.TabHeader((Tabs)Parent, this);
}
}
}

View File

@@ -24,11 +24,6 @@ namespace FlaxEditor.GUI.Tabs
/// </summary>
protected Tabs Tabs;
/// <summary>
/// The index of the tab.
/// </summary>
protected int Index;
/// <summary>
/// The tab.
/// </summary>
@@ -38,21 +33,22 @@ namespace FlaxEditor.GUI.Tabs
/// Initializes a new instance of the <see cref="TabHeader"/> class.
/// </summary>
/// <param name="tabs">The tabs.</param>
/// <param name="index">The tab index.</param>
/// <param name="tab">The tab.</param>
public TabHeader(Tabs tabs, int index, Tab tab)
public TabHeader(Tabs tabs, Tab tab)
: base(Float2.Zero, tabs._tabsSize)
{
Tabs = tabs;
Index = index;
Tab = tab;
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
Tabs.SelectedTabIndex = Index;
Tabs.Focus();
if (EnabledInHierarchy && Tab.Enabled)
{
Tabs.SelectedTab = Tab;
Tabs.Focus();
}
return true;
}
@@ -61,19 +57,20 @@ namespace FlaxEditor.GUI.Tabs
{
base.Draw();
// Cache data
var style = Style.Current;
var enabled = EnabledInHierarchy && Tab.EnabledInHierarchy;
var tabRect = new Rectangle(Float2.Zero, Size);
bool isTabSelected = Tabs._selectedIndex == Index;
bool isMouseOverTab = IsMouseOver;
var textOffset = Tabs._orientation == Orientation.Horizontal ? 0 : 8;
// Draw bar
if (isTabSelected)
if (Tabs.SelectedTab == Tab)
{
var color = style.BackgroundSelected;
if (!enabled)
color *= 0.6f;
if (Tabs._orientation == Orientation.Horizontal)
{
Render2D.FillRectangle(tabRect, style.BackgroundSelected);
Render2D.FillRectangle(tabRect, color);
}
else
{
@@ -84,10 +81,10 @@ namespace FlaxEditor.GUI.Tabs
fillRect.Size.X -= lefEdgeWidth;
fillRect.Location.X += lefEdgeWidth;
Render2D.FillRectangle(fillRect, style.Background);
Render2D.FillRectangle(leftEdgeRect, style.BackgroundSelected);
Render2D.FillRectangle(leftEdgeRect, color);
}
}
else if (isMouseOverTab)
else if (IsMouseOver && enabled)
{
Render2D.FillRectangle(tabRect, style.BackgroundHighlighted);
}
@@ -131,20 +128,15 @@ namespace FlaxEditor.GUI.Tabs
{
base.PerformLayoutBeforeChildren();
// Cache data
var tabsSize = Tabs._tabsSize;
var clientSize = GetClientArea();
tabsSize = Float2.Min(tabsSize, clientSize.Size);
var tabRect = new Rectangle(Float2.Zero, tabsSize);
var tabStripOffset = Tabs._orientation == Orientation.Horizontal ? new Float2(tabsSize.X, 0) : new Float2(0, tabsSize.Y);
// Arrange tab header controls
var pos = Float2.Zero;
var sizeMask = Tabs._orientation == Orientation.Horizontal ? Float2.UnitX : Float2.UnitY;
for (int i = 0; i < Children.Count; i++)
{
if (Children[i] is TabHeader tabHeader)
{
tabHeader.Bounds = tabRect;
tabRect.Offset(tabStripOffset);
tabHeader.Location = pos;
pos += tabHeader.Size * sizeMask;
}
}
}
@@ -160,6 +152,11 @@ namespace FlaxEditor.GUI.Tabs
/// </summary>
protected Float2 _tabsSize;
/// <summary>
/// Automatic tab size based on the fill axis.
/// </summary>
protected bool _autoTabsSizeAuto;
/// <summary>
/// The orientation.
/// </summary>
@@ -174,15 +171,31 @@ namespace FlaxEditor.GUI.Tabs
set
{
_tabsSize = value;
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
if (!_autoTabsSizeAuto)
{
if (TabsPanel.Children[i] is TabHeader tabHeader)
tabHeader.Size = value;
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
{
if (TabsPanel.Children[i] is TabHeader tabHeader)
tabHeader.Size = value;
}
}
PerformLayout();
}
}
/// <summary>
/// Enables automatic tabs size to fill the space.
/// </summary>
public bool AutoTabsSize
{
get => _autoTabsSizeAuto;
set
{
_autoTabsSizeAuto = value;
PerformLayout();
}
}
/// <summary>
/// Gets or sets the orientation.
/// </summary>
@@ -339,14 +352,10 @@ namespace FlaxEditor.GUI.Tabs
// Update tabs headers
TabsPanel.DisposeChildren();
int index = 0;
for (int i = 0; i < Children.Count; i++)
{
if (Children[i] is Tab tab)
{
var tabHeader = new TabHeader(this, index++, tab);
TabsPanel.AddChild(tabHeader);
}
TabsPanel.AddChild(tab.CreateHeader());
}
TabsPanel.IsLayoutLocked = wasLocked;
@@ -371,23 +380,46 @@ namespace FlaxEditor.GUI.Tabs
/// <inheritdoc />
protected override void PerformLayoutBeforeChildren()
{
var tabsSize = _tabsSize;
if (_autoTabsSizeAuto)
{
// Horizontal is default for Toolbox so tabs go to the right
int tabsCount = 0;
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
{
if (TabsPanel.Children[i] is TabHeader)
tabsCount++;
}
if (tabsCount == 0)
tabsCount = 1;
if (_orientation == Orientation.Horizontal)
tabsSize.X = Width / tabsCount;
else
tabsSize.Y = Height / tabsCount;
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
{
if (TabsPanel.Children[i] is TabHeader tabHeader)
tabHeader.Size = tabsSize;
}
}
// Fit the tabs panel
TabsPanel.Size = _orientation == Orientation.Horizontal ? new Float2(Width, _tabsSize.Y) : new Float2(_tabsSize.X, Height);
TabsPanel.Size = _orientation == Orientation.Horizontal
? new Float2(Width, tabsSize.Y)
: new Float2(tabsSize.X, Height);
// Hide all pages except selected one
var clientArea = _orientation == Orientation.Horizontal
? new Rectangle(0, _tabsSize.Y, Width, Height - _tabsSize.Y)
: new Rectangle(_tabsSize.X, 0, Width - _tabsSize.X, Height);
for (int i = 0; i < Children.Count; i++)
{
if (Children[i] is Tab tab)
{
// Check if is selected or not
if (i - 1 == _selectedIndex)
{
// Show and fit size
tab.Visible = true;
tab.Bounds = clientArea;
tab.Bounds = _orientation == Orientation.Horizontal
? new Rectangle(0, tabsSize.Y, Width, Height - tabsSize.Y)
: new Rectangle(tabsSize.X, 0, Width - tabsSize.X, Height);
}
else
{