c6a1cedd97dededcc40cd1bc1216372b09392e65
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / TabBar.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.Collections.Generic;
19 using System.ComponentModel;
20 using Tizen.NUI.BaseComponents;
21
22 namespace Tizen.NUI.Components
23 {
24     /// <summary>
25     /// TabButtonSelectedEventArgs is a class to record tab button selected event
26     /// arguments which will be sent to a user.
27     /// </summary>
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public class TabButtonSelectedEventArgs : EventArgs
30     {
31         /// <summary>
32         /// Creates a new instance of TabButtonSelectedEventArgs.
33         /// The indices of tab buttons in TabBar are basically the order of adding to TabBar by <see cref="TabView.AddTab"/>.
34         /// So a tab button's index in TabBar can be changed whenever <see cref="TabView.AddTab"/> or <see cref="TabView.RemoveTab"/> is called.
35         /// </summary>
36         /// <param name="index">The index of the selected tab button in TabBar.</param>
37         [EditorBrowsable(EditorBrowsableState.Never)]
38         public TabButtonSelectedEventArgs(int index)
39         {
40             Index = index;
41         }
42
43         /// <summary>
44         /// The index of the selected tab button.
45         /// </summary>
46         [EditorBrowsable(EditorBrowsableState.Never)]
47         public int Index { get; }
48     }
49
50     /// <summary>
51     /// TabBar is a class which contains a set of TabButtons and has one of them selected.
52     /// </summary>
53     /// <since_tizen> 9 </since_tizen>
54     public class TabBar : Control
55     {
56         private IList<TabButton> tabButtons;
57
58         private TabButtonGroup tabButtonGroup;
59
60         /// <summary>
61         /// Creates a new instance of TabBar.
62         /// </summary>
63         /// <since_tizen> 9 </since_tizen>
64         public TabBar()
65         {
66             Layout = new LinearLayout() { LinearOrientation = LinearLayout.Orientation.Horizontal };
67
68             WidthSpecification = LayoutParamPolicies.MatchParent;
69
70             tabButtons = new List<TabButton>();
71             tabButtonGroup = new TabButtonGroup();
72             SelectedIndex = -1;
73         }
74
75         /// <summary>
76         /// An event for the tab button selected signal which can be used to
77         /// subscribe or unsubscribe the event handler provided by a user.
78         /// </summary>
79         [EditorBrowsable(EditorBrowsableState.Never)]
80         public event EventHandler<TabButtonSelectedEventArgs> TabButtonSelected;
81
82         /// <summary>
83         /// The index of the selected tab button.
84         /// The indices of tab buttons in TabBar are basically the order of adding to TabBar by <see cref="TabView.AddTab"/>.
85         /// So a tab button's index in TabBar can be changed whenever <see cref="TabView.AddTab"/> or <see cref="TabView.RemoveTab"/> is called.
86         /// </summary>
87         [EditorBrowsable(EditorBrowsableState.Never)]
88         protected int SelectedIndex { get; set; }
89
90         /// <summary>
91         /// Gets the count of tab buttons.
92         /// </summary>
93         /// <since_tizen> 9 </since_tizen>
94         public int TabButtonCount => tabButtons.Count;
95
96         /// <inheritdoc/>
97         [EditorBrowsable(EditorBrowsableState.Never)]
98         public override void OnInitialize()
99         {
100             base.OnInitialize();
101
102             AccessibilityRole = Role.PageTabList;
103         }
104
105         /// <summary>
106         /// Adds a tab button to TabBar.
107         /// </summary>
108         /// <param name="tabButton">A tab button to be added to TabBar.</param>
109         /// <exception cref="ArgumentNullException">Thrown when the argument tabButton is null.</exception>
110         [EditorBrowsable(EditorBrowsableState.Never)]
111         protected internal void AddTabButton(TabButton tabButton)
112         {
113             if (tabButton == null)
114             {
115                 throw new ArgumentNullException(nameof(tabButton), "tabButton should not be null.");
116             }
117
118             tabButtons.Add(tabButton);
119             Add(tabButton);
120             tabButtonGroup.Add(tabButton);
121
122             tabButton.Clicked += (object sender, ClickedEventArgs e) =>
123             {
124                 int index = tabButtons.IndexOf(tabButton);
125
126                 if (SelectedIndex == index)
127                 {
128                     return;
129                 }
130
131                 SelectedIndex = index;
132
133                 if (TabButtonSelected != null)
134                 {
135                     TabButtonSelectedEventArgs args = new TabButtonSelectedEventArgs(SelectedIndex);
136                     TabButtonSelected(this, args);
137                 }
138             };
139
140             if (SelectedIndex == -1)
141             {
142                 tabButton.IsSelected = true;
143                 SelectedIndex = 0;
144
145                 if (TabButtonSelected != null)
146                 {
147                     TabButtonSelectedEventArgs args = new TabButtonSelectedEventArgs(SelectedIndex);
148                     TabButtonSelected(this, args);
149                 }
150             }
151
152             //TODO: To support non-unified tab button size.
153             CalculateUnifiedTabButtonSize();
154         }
155
156         /// <summary>
157         /// Removes a tab button from TabBar.
158         /// </summary>
159         /// <param name="tabButton">A tab button to be removed from TabBar.</param>
160         /// <exception cref="ArgumentNullException">Thrown when the argument tabButton is null.</exception>
161         /// <exception cref="ArgumentException">Thrown when the argument tabButton does not exist in TabBar.</exception>
162         [EditorBrowsable(EditorBrowsableState.Never)]
163         protected internal void RemoveTabButton(TabButton tabButton)
164         {
165             if (tabButton == null)
166             {
167                 throw new ArgumentNullException(nameof(tabButton), "tabButton should not be null.");
168             }
169
170             if (tabButtons.Contains(tabButton) == false)
171             {
172                 throw new ArgumentException("tabButton does not exist in TabBar.", nameof(tabButton));
173             }
174
175             int index = tabButtons.IndexOf(tabButton);
176             TabButton selectedTabButton = tabButtons[SelectedIndex];
177
178             tabButtons.Remove(tabButton);
179             Remove(tabButton);
180             tabButtonGroup.Remove(tabButton);
181
182             if ((index < SelectedIndex) || (tabButtons.Count == SelectedIndex))
183             {
184                 SelectedIndex -= 1;
185
186                 if (TabButtonSelected != null)
187                 {
188                     TabButtonSelectedEventArgs args = new TabButtonSelectedEventArgs(SelectedIndex);
189                     TabButtonSelected(this, args);
190                 }
191             }
192
193             if ((SelectedIndex != -1) && (selectedTabButton != tabButtons[SelectedIndex]))
194             {
195                 tabButtons[SelectedIndex].IsSelected = true;
196             }
197
198             //TODO: To support non-unified tab button size.
199             CalculateUnifiedTabButtonSize();
200         }
201
202         /// <inheritdoc/>
203         [EditorBrowsable(EditorBrowsableState.Never)]
204         public override void OnRelayout(Vector2 size, RelayoutContainer container)
205         {
206             base.OnRelayout(size, container);
207
208             //TODO: To support non-unified tab button size.
209             CalculateUnifiedTabButtonSize();
210         }
211
212         private void CalculateUnifiedTabButtonSize()
213         {
214             if (tabButtons.Count <= 0)
215             {
216                 return;
217             }
218
219             var tabButtonWidth = Size.Width / tabButtons.Count;
220
221             foreach (TabButton tabButton in tabButtons)
222             {
223                 if (tabButton.Size.Width != tabButtonWidth)
224                 {
225                     tabButton.Size = new Size(tabButtonWidth, tabButton.Size.Height);
226                 }
227             }
228         }
229
230         /// <summary>
231         /// Gets the tab button at the specified index of TabBar.
232         /// The indices of tab buttons in TabBar are basically the order of adding to TabBar by <see cref="TabView.AddTab"/>.
233         /// So a tab button's index in TabBar can be changed whenever <see cref="TabView.AddTab"/> or <see cref="TabView.RemoveTab"/> is called.
234         /// </summary>
235         /// <param name="index">The index of tab button in TabBar where the specified tab button exists.</param>
236         /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is less than 0, or greater than or equal to the number of tab buttons.</exception>
237         /// <since_tizen> 9 </since_tizen>
238         public TabButton GetTabButton(int index)
239         {
240             if ((index < 0) || (index >= tabButtons.Count))
241             {
242                 throw new ArgumentOutOfRangeException(nameof(index), "index should not be greater than or equal to 0, and less than the number of tab buttons.");
243             }
244
245             return tabButtons[index];
246         }
247
248         /// <inheritdoc/>
249         [EditorBrowsable(EditorBrowsableState.Never)]
250         protected override void Dispose(DisposeTypes type)
251         {
252             if (disposed)
253             {
254                 return;
255             }
256
257             if (type == DisposeTypes.Explicit)
258             {
259                 if (tabButtons != null)
260                 {
261                     foreach (TabButton tabButton in tabButtons)
262                     {
263                         Utility.Dispose(tabButton);
264                     }
265
266                     tabButtons = null;
267                 }
268
269                 tabButtonGroup = null;
270             }
271
272             base.Dispose(type);
273         }
274     }
275 }