TabView.cs
5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Unity.Cloud.Collaborate.Assets;
using Unity.Cloud.Collaborate.UserInterface;
using UnityEditor;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UIElements;
namespace Unity.Cloud.Collaborate.Components
{
[UsedImplicitly]
internal class TabView : VisualElement
{
public const string UssClassName = "unity-tab-view";
public const string ContentContainerUssClassName = UssClassName + "__content-container";
public const string TabHeaderUssClassName = UssClassName + "__tab-header";
public const string ToolbarUssClassName = UssClassName + "__toolbar";
static readonly string k_StylePath = $"{CollaborateWindow.StylePath}/{nameof(TabView)}.uss";
const int k_NoTabs = -1;
int m_ActiveTabIndex = k_NoTabs;
bool m_Active;
readonly VisualElement m_Content;
readonly VisualElement m_Toolbar;
readonly List<(TextButton button, TabPageComponent tab)> m_TabList;
public event Action<int> TabSwitched;
public TabView()
{
AddToClassList(UssClassName);
styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>(k_StylePath));
m_Toolbar = new VisualElement { name = "unity-tab-view-toolbar" };
m_Toolbar.AddToClassList(ToolbarUssClassName);
m_Toolbar.AddToClassList(UiConstants.ussDefaultInset);
hierarchy.Add(m_Toolbar);
m_Content = new VisualElement { name = "unity-content-container" };
m_Content.AddToClassList(ContentContainerUssClassName);
hierarchy.Add(m_Content);
m_TabList = new List<(TextButton button, TabPageComponent tab)>();
}
public void SetActive()
{
Assert.IsFalse(m_Active, "TabView is already active.");
m_Active = true;
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(true);
}
}
public void SetInactive()
{
Assert.IsTrue(m_Active, "TabView is already inactive.");
m_Active = false;
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(false);
}
}
/// <summary>
/// Add a tab to the view.
/// </summary>
/// <param name="tabName">Title of the tab.</param>
/// <param name="tab">Tab content to display.</param>
public void AddTab(string tabName, TabPageComponent tab)
{
// Get the tab index
var index = m_TabList.Count;
tab.style.flexGrow = 1;
tab.style.flexShrink = 1;
tab.style.flexBasis = new StyleLength(StyleKeyword.Auto);
// Copy value to avoid modification of the closure scope.
var indexCopy = index;
var btn = new TextButton(() => SwitchTabInternal(indexCopy)) { text = tabName };
btn.AddToClassList(TabHeaderUssClassName);
m_Toolbar.Add(btn);
// Add tab to list
m_TabList.Add((btn, tab));
// If no currently active tab, switch to this newly added one.
if (m_ActiveTabIndex == k_NoTabs)
{
SwitchToNextTab();
}
}
/// <summary>
/// Switch to the tab with the given index. Does nothing with an invalid index.
/// </summary>
/// <param name="index">Index of the tab to switch to.</param>
public void SwitchTab(int index)
{
// Sanitise index to be passed into the internal switch method.
if (index == k_NoTabs) return;
if (index < m_TabList.Count)
{
SwitchTabInternal(index);
}
}
/// <summary>
/// Switch to tab with the given index. Does *NOT* check the validity of the index.
/// </summary>
/// <param name="index">Index of the tab to switch to.</param>
void SwitchTabInternal(int index)
{
// Reset tab state of previously active content/button - if there was one.
if (m_ActiveTabIndex != k_NoTabs)
{
m_TabList[m_ActiveTabIndex].tab.RemoveFromHierarchy();
if (m_Active)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(false);
}
m_TabList[m_ActiveTabIndex].button.RemoveFromClassList(UiConstants.ussActive);
}
// Set new active tab.
m_ActiveTabIndex = index;
// Set tab state for newly active content/button.
if (m_Active)
{
m_TabList[m_ActiveTabIndex].tab.SetActive(true);
}
m_TabList[m_ActiveTabIndex].button.AddToClassList(UiConstants.ussActive);
m_Content.Add(m_TabList[m_ActiveTabIndex].tab);
TabSwitched?.Invoke(index);
}
/// <summary>
/// Switch to the next valid tab. Wraps if there's no direct successor.
/// </summary>
void SwitchToNextTab()
{
var index = (m_ActiveTabIndex + 1) % m_TabList.Count;
SwitchTabInternal(index);
}
public override VisualElement contentContainer => m_Content;
[UsedImplicitly]
public new class UxmlFactory : UxmlFactory<TabView> { }
}
}