2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections.Generic;
19 using Tizen.NUI.BaseComponents;
20 using System.ComponentModel;
22 namespace Tizen.NUI.Components
25 /// Tab is one kind of common component, it can be used as menu label.
26 /// User can handle Tab by adding/inserting/deleting TabItem.
28 /// <since_tizen> 6 </since_tizen>
29 public class Tab : Control
31 private const int aniTime = 100; // will be defined in const file later
32 private List<TabItem> itemList = new List<TabItem>();
33 private int curIndex = 0;
34 private View underline = null;
35 private TabAttributes tabAttributes = null;
36 private Animation underlineAni = null;
37 private bool isNeedAnimation = false;
38 private Extents space;
41 /// Creates a new instance of a Tab.
43 /// <since_tizen> 6 </since_tizen>
50 /// Creates a new instance of a Tab with style.
52 /// <param name="style">Create Tab by special style defined in UX.</param>
53 /// <since_tizen> 6 </since_tizen>
54 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
55 [EditorBrowsable(EditorBrowsableState.Never)]
56 public Tab(string style) : base(style)
62 /// Creates a new instance of a Tab with attributes.
64 /// <param name="attributes">Create Tab by attributes customized by user.</param>
65 /// <since_tizen> 6 </since_tizen>
66 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public Tab(TabAttributes attributes) : base(attributes)
74 /// An event for the item changed signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
76 /// <since_tizen> 6 </since_tizen>
77 public event EventHandler<ItemChangedEventArgs> ItemChangedEvent;
80 /// Selected item's index in Tab.
82 /// <since_tizen> 6 </since_tizen>
83 public int SelectedItemIndex
91 if (value < itemList.Count)
93 UpdateSelectedItem(itemList[value]);
99 /// Flag to decide if TabItem is adjusted by text's natural width.
100 /// If true, TabItem's width will be equal as text's natural width, if false, it will be decided by Tab's width and tab item count.
102 /// <since_tizen> 6 </since_tizen>
103 public bool UseTextNaturalSize
107 return tabAttributes.UseTextNaturalSize;
111 tabAttributes.UseTextNaturalSize = value;
117 /// Gap between items.
119 /// <since_tizen> 6 </since_tizen>
124 return tabAttributes.ItemSpace;
128 tabAttributes.ItemSpace = value;
134 /// Space in Tab. Sequence as Left, Right, Top, Bottom
136 /// <since_tizen> 6 </since_tizen>
147 tabAttributes.Space.CopyFrom(value);
151 space = new Extents((ushort start, ushort end, ushort top, ushort bottom) =>
153 tabAttributes.Space.Start = start;
154 tabAttributes.Space.End = end;
155 tabAttributes.Space.Top = top;
156 tabAttributes.Space.Bottom = bottom;
158 }, value.Start, value.End, value.Top, value.Bottom);
162 space.CopyFrom(value);
171 /// UnderLine view's size in Tab.
173 /// <since_tizen> 6 </since_tizen>
174 public Size UnderLineSize
178 return tabAttributes.UnderLineAttributes?.Size;
184 CreateUnderLineAttributes();
185 tabAttributes.UnderLineAttributes.Size = value;
192 /// UnderLine view's background in Tab.
194 /// <since_tizen> 6 </since_tizen>
195 public Color UnderLineBackgroundColor
199 return tabAttributes.UnderLineAttributes?.BackgroundColor?.All;
205 CreateUnderLineAttributes();
206 if (tabAttributes.UnderLineAttributes.BackgroundColor == null)
208 tabAttributes.UnderLineAttributes.BackgroundColor = new ColorSelector();
210 tabAttributes.UnderLineAttributes.BackgroundColor.All = value;
217 /// Text point size in Tab.
219 /// <since_tizen> 6 </since_tizen>
220 public float PointSize
224 return tabAttributes.TextAttributes?.PointSize?.All ?? 0;
228 CreateTextAttributes();
229 if (tabAttributes.TextAttributes.PointSize == null)
231 tabAttributes.TextAttributes.PointSize = new FloatSelector();
233 tabAttributes.TextAttributes.PointSize.All = value;
239 /// Text font family in Tab.
241 /// <since_tizen> 6 </since_tizen>
242 public string FontFamily
246 return tabAttributes.TextAttributes?.FontFamily;
250 CreateTextAttributes();
251 tabAttributes.TextAttributes.FontFamily = value;
257 /// Text color in Tab.
259 /// <since_tizen> 6 </since_tizen>
260 public Color TextColor
264 return tabAttributes.TextAttributes?.TextColor?.All;
268 CreateTextAttributes();
269 if (tabAttributes.TextAttributes.TextColor == null)
271 tabAttributes.TextAttributes.TextColor = new ColorSelector();
273 tabAttributes.TextAttributes.TextColor.All = value;
279 /// Text color selector in Tab.
281 /// <since_tizen> 6 </since_tizen>
282 public ColorSelector TextColorSelector
286 return tabAttributes.TextAttributes.TextColor;
292 CreateTextAttributes();
293 tabAttributes.TextAttributes.TextColor = value.Clone() as ColorSelector;
300 /// Add tab item by item data. The added item will be added to end of all items automatically.
302 /// <param name="itemData">Item data which will apply to tab item view.</param>
303 /// <since_tizen> 6 </since_tizen>
304 public void AddItem(TabItemData itemData)
306 AddItemByIndex(itemData, itemList.Count);
310 /// Insert tab item by item data. The inserted item will be added to the special position by index automatically.
312 /// <param name="itemData">Item data which will apply to tab item view.</param>
313 /// <param name="index">Position index where will be inserted.</param>
314 /// <since_tizen> 6 </since_tizen>
315 public void InsertItem(TabItemData itemData, int index)
317 AddItemByIndex(itemData, index);
321 /// Delete tab item by index.
323 /// <param name="itemIndex">Position index where will be deleted.</param>
324 /// <since_tizen> 6 </since_tizen>
325 public void DeleteItem(int itemIndex)
327 if(itemList == null || itemIndex < 0 || itemIndex >= itemList.Count)
332 if (curIndex > itemIndex || (curIndex == itemIndex && itemIndex == itemList.Count - 1))
337 Remove(itemList[itemIndex]);
338 itemList[itemIndex].Dispose();
339 itemList.RemoveAt(itemIndex);
345 /// Dispose Tab and all children on it.
347 /// <param name="type">Dispose type.</param>
348 /// <since_tizen> 6 </since_tizen>
349 protected override void Dispose(DisposeTypes type)
356 if (type == DisposeTypes.Explicit)
358 if(underlineAni != null)
360 if(underlineAni.State == Animation.States.Playing)
364 underlineAni.Dispose();
367 Utility.Dispose(underline);
370 for(int i = 0; i < itemList.Count; i++)
373 itemList[i].Dispose();
385 /// Update Tab by attributes.
387 /// <since_tizen> 6 </since_tizen>
388 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
389 [EditorBrowsable(EditorBrowsableState.Never)]
390 protected override void OnUpdate()
392 if (tabAttributes.UnderLineAttributes != null)
394 if (underline == null)
396 underline = new View()
398 PositionUsesPivotPoint = true,
399 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
400 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
403 CreateUnderLineAnimation();
405 ApplyAttributes(underline, tabAttributes.UnderLineAttributes);
408 if (tabAttributes.TextAttributes != null)
410 if (curIndex >= 0 && curIndex < itemList.Count)
412 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
420 /// Get Tab attribues.
422 /// <since_tizen> 6 </since_tizen>
423 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
424 [EditorBrowsable(EditorBrowsableState.Never)]
425 protected override Attributes GetAttributes()
427 return new TabAttributes();
431 /// Theme change callback when theme is changed, this callback will be trigger.
433 /// <since_tizen> 6 </since_tizen>
434 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
435 [EditorBrowsable(EditorBrowsableState.Never)]
436 protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
438 TabAttributes tempAttributes = StyleManager.Instance.GetAttributes(style) as TabAttributes;
439 if (tempAttributes != null)
441 tempAttributes.UseTextNaturalSize = tabAttributes.UseTextNaturalSize; // keep IsNatureTextWidth as original
442 attributes = tabAttributes = tempAttributes;
448 /// Layout child in Tab and it can be override by user.
450 /// <since_tizen> 6 </since_tizen>
451 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
452 [EditorBrowsable(EditorBrowsableState.Never)]
453 protected virtual void LayoutChild()
455 if (tabAttributes == null || itemList == null)
459 int totalNum = itemList.Count;
465 int preX = (int)tabAttributes.Space.Start;
467 int itemSpace = tabAttributes.ItemSpace;
469 if (LayoutDirection == ViewLayoutDirectionType.LTR)
471 if (tabAttributes.UseTextNaturalSize == true)
473 for (int i = 0; i < totalNum; i++)
475 preW = (itemList[i].TextItem.NaturalSize2D != null ? itemList[i].TextItem.NaturalSize2D.Width : 0);
476 itemList[i].Position2D.X = preX;
477 itemList[i].Size2D.Width = preW;
478 preX = itemList[i].Position2D.X + preW + itemSpace;
479 itemList[i].Index = i;
484 preW = (Size2D.Width - (int)tabAttributes.Space.Start - (int)tabAttributes.Space.End) / totalNum;
485 for (int i = 0; i < totalNum; i++)
487 itemList[i].Position2D.X = preX;
488 itemList[i].Size2D.Width = preW;
489 preX = itemList[i].Position2D.X + preW + itemSpace;
490 itemList[i].Index = i;
496 preX = (int)tabAttributes.Space.End;
497 if (tabAttributes.UseTextNaturalSize == true)
499 int w = Size2D.Width;
500 for (int i = 0; i < totalNum; i++)
502 preW = (itemList[i].TextItem.NaturalSize2D != null ? itemList[i].TextItem.NaturalSize2D.Width : 0);
503 itemList[i].Position2D.X = w - preW - preX;
504 itemList[i].Size2D.Width = preW;
505 preX = w - itemList[i].Position2D.X + itemSpace;
506 itemList[i].Index = i;
511 preW = (Size2D.Width - (int)tabAttributes.Space.Start - (int)tabAttributes.Space.End) / totalNum;
512 for (int i = totalNum - 1; i >= 0; i--)
514 itemList[i].Position2D.X = preX;
515 itemList[i].Size2D.Width = preW;
516 preX = itemList[i].Position2D.X + preW + itemSpace;
517 itemList[i].Index = i;
521 UpdateUnderLinePos();
524 private void Initialize()
526 tabAttributes = attributes as TabAttributes;
527 if (tabAttributes == null)
529 throw new Exception("Tab attribute parse error.");
532 ApplyAttributes(this, tabAttributes);
533 LayoutDirectionChanged += OnLayoutDirectionChanged;
536 private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
541 private void AddItemByIndex(TabItemData itemData, int index)
544 int topSpace = (int)tabAttributes.Space.Top;
545 if (tabAttributes.UnderLineAttributes != null && tabAttributes.UnderLineAttributes.Size != null)
547 h = (int)tabAttributes.UnderLineAttributes.Size.Height;
549 Tab.TabItem item = new TabItem();
550 ApplyAttributes(item.TextItem, tabAttributes.TextAttributes);
551 item.TextItem.Text = itemData.Text;
552 item.Size2D.Height = Size2D.Height - h - topSpace;
553 item.Position2D.Y = topSpace;
554 item.TouchEvent += ItemTouchEvent;
557 if(index >= itemList.Count)
563 itemList.Insert(index, item);
569 private void UpdateItems()
572 if (itemList != null && curIndex >= 0 && curIndex < itemList.Count)
574 itemList[curIndex].State = ControlStates.Selected;
575 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
576 UpdateUnderLinePos();
580 if (underline != null)
587 private void CreateUnderLineAttributes()
589 if (tabAttributes.UnderLineAttributes == null)
591 tabAttributes.UnderLineAttributes = new ViewAttributes()
593 PositionUsesPivotPoint = true,
594 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
595 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
600 private void CreateTextAttributes()
602 if (tabAttributes.TextAttributes == null)
604 tabAttributes.TextAttributes = new TextAttributes()
606 PositionUsesPivotPoint = true,
607 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
608 PivotPoint = Tizen.NUI.PivotPoint.Center,
609 HorizontalAlignment = HorizontalAlignment.Center,
610 VerticalAlignment = VerticalAlignment.Center,
611 WidthResizePolicy = ResizePolicyType.FillToParent,
612 HeightResizePolicy = ResizePolicyType.FillToParent
617 private void CreateUnderLineAnimation()
619 if (underlineAni == null)
621 underlineAni = new Animation(aniTime);
625 private void UpdateUnderLinePos()
627 if (underline == null || tabAttributes.UnderLineAttributes == null || tabAttributes.UnderLineAttributes.Size == null
628 || itemList == null || itemList.Count <= 0)
633 tabAttributes.UnderLineAttributes.Size.Width = itemList[curIndex].Size2D.Width;
635 underline.Size2D = new Size2D(itemList[curIndex].Size2D.Width, (int)tabAttributes.UnderLineAttributes.Size.Height);
636 underline.BackgroundColor = tabAttributes.UnderLineAttributes.BackgroundColor.All;
639 CreateUnderLineAnimation();
640 if (underlineAni.State == Animation.States.Playing)
644 underlineAni.Clear();
645 underlineAni.AnimateTo(underline, "PositionX", itemList[curIndex].Position2D.X);
650 underline.Position2D.X = itemList[curIndex].Position2D.X;
651 isNeedAnimation = true;
657 private void UpdateSelectedItem(TabItem item)
659 if(item == null || curIndex == item.Index)
664 ItemChangedEventArgs e = new ItemChangedEventArgs
666 PreviousIndex = curIndex,
667 CurrentIndex = item.Index
669 ItemChangedEvent?.Invoke(this, e);
671 itemList[curIndex].State = ControlStates.Normal;
672 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
673 curIndex = item.Index;
674 itemList[curIndex].State = ControlStates.Selected;
675 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
677 UpdateUnderLinePos();
680 private bool ItemTouchEvent(object source, TouchEventArgs e)
682 TabItem item = source as TabItem;
687 PointStateType state = e.Touch.GetState(0);
688 if (state == PointStateType.Up)
690 UpdateSelectedItem(item);
696 internal class TabItem : Control
698 public TabItem() : base()
700 TextItem = new TextLabel()
702 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
703 PivotPoint = Tizen.NUI.PivotPoint.Center,
704 PositionUsesPivotPoint = true,
705 WidthResizePolicy = ResizePolicyType.FillToParent,
706 HeightResizePolicy = ResizePolicyType.FillToParent,
707 HorizontalAlignment = HorizontalAlignment.Center,
708 VerticalAlignment = VerticalAlignment.Center
717 return TextItem.Text;
721 TextItem.Text = value;
731 internal TextLabel TextItem
737 protected override void Dispose(DisposeTypes type)
744 if (type == DisposeTypes.Explicit)
746 if (TextItem != null)
757 protected override Attributes GetAttributes()
762 internal void UpdateItemText(TextAttributes attrs)
764 ApplyAttributes(TextItem, attrs);
769 /// TabItemData is a class to record all data which will be applied to Tab item.
771 /// <since_tizen> 6 </since_tizen>
772 public class TabItemData
775 /// Text string in tab item view.
777 /// <since_tizen> 6 </since_tizen>
786 /// ItemChangedEventArgs is a class to record item change event arguments which will sent to user.
788 /// <since_tizen> 6 </since_tizen>
789 public class ItemChangedEventArgs : EventArgs
791 /// <summary> Previous selected index of Tab </summary>
792 /// <since_tizen> 6 </since_tizen>
793 public int PreviousIndex;
794 /// <summary> Current selected index of Tab </summary>
795 /// <since_tizen> 6 </since_tizen>
796 public int CurrentIndex;