Refactor Editor Tab controls system to allows customizing the tab header controls
This commit is contained in:
@@ -77,5 +77,14 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
{
|
{
|
||||||
Deselected?.Invoke(this);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Tabs Tabs;
|
protected Tabs Tabs;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The index of the tab.
|
|
||||||
/// </summary>
|
|
||||||
protected int Index;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tab.
|
/// The tab.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -38,21 +33,22 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
/// Initializes a new instance of the <see cref="TabHeader"/> class.
|
/// Initializes a new instance of the <see cref="TabHeader"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tabs">The tabs.</param>
|
/// <param name="tabs">The tabs.</param>
|
||||||
/// <param name="index">The tab index.</param>
|
|
||||||
/// <param name="tab">The tab.</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)
|
: base(Float2.Zero, tabs._tabsSize)
|
||||||
{
|
{
|
||||||
Tabs = tabs;
|
Tabs = tabs;
|
||||||
Index = index;
|
|
||||||
Tab = tab;
|
Tab = tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||||
{
|
{
|
||||||
Tabs.SelectedTabIndex = Index;
|
if (EnabledInHierarchy && Tab.Enabled)
|
||||||
Tabs.Focus();
|
{
|
||||||
|
Tabs.SelectedTab = Tab;
|
||||||
|
Tabs.Focus();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,19 +57,20 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
{
|
{
|
||||||
base.Draw();
|
base.Draw();
|
||||||
|
|
||||||
// Cache data
|
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
|
var enabled = EnabledInHierarchy && Tab.EnabledInHierarchy;
|
||||||
var tabRect = new Rectangle(Float2.Zero, Size);
|
var tabRect = new Rectangle(Float2.Zero, Size);
|
||||||
bool isTabSelected = Tabs._selectedIndex == Index;
|
|
||||||
bool isMouseOverTab = IsMouseOver;
|
|
||||||
var textOffset = Tabs._orientation == Orientation.Horizontal ? 0 : 8;
|
var textOffset = Tabs._orientation == Orientation.Horizontal ? 0 : 8;
|
||||||
|
|
||||||
// Draw bar
|
// Draw bar
|
||||||
if (isTabSelected)
|
if (Tabs.SelectedTab == Tab)
|
||||||
{
|
{
|
||||||
|
var color = style.BackgroundSelected;
|
||||||
|
if (!enabled)
|
||||||
|
color *= 0.6f;
|
||||||
if (Tabs._orientation == Orientation.Horizontal)
|
if (Tabs._orientation == Orientation.Horizontal)
|
||||||
{
|
{
|
||||||
Render2D.FillRectangle(tabRect, style.BackgroundSelected);
|
Render2D.FillRectangle(tabRect, color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -84,10 +81,10 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
fillRect.Size.X -= lefEdgeWidth;
|
fillRect.Size.X -= lefEdgeWidth;
|
||||||
fillRect.Location.X += lefEdgeWidth;
|
fillRect.Location.X += lefEdgeWidth;
|
||||||
Render2D.FillRectangle(fillRect, style.Background);
|
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);
|
Render2D.FillRectangle(tabRect, style.BackgroundHighlighted);
|
||||||
}
|
}
|
||||||
@@ -131,20 +128,15 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
{
|
{
|
||||||
base.PerformLayoutBeforeChildren();
|
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
|
// 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++)
|
for (int i = 0; i < Children.Count; i++)
|
||||||
{
|
{
|
||||||
if (Children[i] is TabHeader tabHeader)
|
if (Children[i] is TabHeader tabHeader)
|
||||||
{
|
{
|
||||||
tabHeader.Bounds = tabRect;
|
tabHeader.Location = pos;
|
||||||
tabRect.Offset(tabStripOffset);
|
pos += tabHeader.Size * sizeMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,6 +152,11 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Float2 _tabsSize;
|
protected Float2 _tabsSize;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Automatic tab size based on the fill axis.
|
||||||
|
/// </summary>
|
||||||
|
protected bool _autoTabsSizeAuto;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The orientation.
|
/// The orientation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -174,15 +171,31 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_tabsSize = value;
|
_tabsSize = value;
|
||||||
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
|
if (!_autoTabsSizeAuto)
|
||||||
{
|
{
|
||||||
if (TabsPanel.Children[i] is TabHeader tabHeader)
|
for (int i = 0; i < TabsPanel.ChildrenCount; i++)
|
||||||
tabHeader.Size = value;
|
{
|
||||||
|
if (TabsPanel.Children[i] is TabHeader tabHeader)
|
||||||
|
tabHeader.Size = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables automatic tabs size to fill the space.
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoTabsSize
|
||||||
|
{
|
||||||
|
get => _autoTabsSizeAuto;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_autoTabsSizeAuto = value;
|
||||||
|
PerformLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the orientation.
|
/// Gets or sets the orientation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -339,14 +352,10 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
|
|
||||||
// Update tabs headers
|
// Update tabs headers
|
||||||
TabsPanel.DisposeChildren();
|
TabsPanel.DisposeChildren();
|
||||||
int index = 0;
|
|
||||||
for (int i = 0; i < Children.Count; i++)
|
for (int i = 0; i < Children.Count; i++)
|
||||||
{
|
{
|
||||||
if (Children[i] is Tab tab)
|
if (Children[i] is Tab tab)
|
||||||
{
|
TabsPanel.AddChild(tab.CreateHeader());
|
||||||
var tabHeader = new TabHeader(this, index++, tab);
|
|
||||||
TabsPanel.AddChild(tabHeader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TabsPanel.IsLayoutLocked = wasLocked;
|
TabsPanel.IsLayoutLocked = wasLocked;
|
||||||
@@ -371,23 +380,46 @@ namespace FlaxEditor.GUI.Tabs
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void PerformLayoutBeforeChildren()
|
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
|
// 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
|
// 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++)
|
for (int i = 0; i < Children.Count; i++)
|
||||||
{
|
{
|
||||||
if (Children[i] is Tab tab)
|
if (Children[i] is Tab tab)
|
||||||
{
|
{
|
||||||
// Check if is selected or not
|
|
||||||
if (i - 1 == _selectedIndex)
|
if (i - 1 == _selectedIndex)
|
||||||
{
|
{
|
||||||
// Show and fit size
|
// Show and fit size
|
||||||
tab.Visible = true;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user