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;
40 /// Creates a new instance of a Tab.
42 /// <since_tizen> 6 </since_tizen>
49 /// Creates a new instance of a Tab with style.
51 /// <param name="style">Create Tab by special style defined in UX.</param>
52 /// <since_tizen> 6 </since_tizen>
53 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 public Tab(string style) : base(style)
61 /// Creates a new instance of a Tab with attributes.
63 /// <param name="attributes">Create Tab by attributes customized by user.</param>
64 /// <since_tizen> 6 </since_tizen>
65 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
66 [EditorBrowsable(EditorBrowsableState.Never)]
67 public Tab(TabAttributes attributes) : base(attributes)
73 /// An event for the item changed signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
75 /// <since_tizen> 6 </since_tizen>
76 public event EventHandler<ItemChangedEventArgs> ItemChangedEvent;
79 /// Selected item's index in Tab.
81 /// <since_tizen> 6 </since_tizen>
82 public int SelectedItemIndex
90 if (value < itemList.Count)
92 UpdateSelectedItem(itemList[value]);
98 /// Flag to decide if TabItem is adjusted by text's natural width.
99 /// 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.
101 /// <since_tizen> 6 </since_tizen>
102 public bool UseTextNaturalSize
106 return tabAttributes.UseTextNaturalSize;
110 tabAttributes.UseTextNaturalSize = value;
116 /// Gap between items.
118 /// <since_tizen> 6 </since_tizen>
123 return tabAttributes.ItemSpace;
127 tabAttributes.ItemSpace = value;
133 /// Space in Tab. Sequence as Left, Right, Top, Bottom
135 /// <since_tizen> 6 </since_tizen>
140 if(null == tabAttributes || null == tabAttributes.Space)
146 return new Extents((ushort)tabAttributes.Space.X, (ushort)tabAttributes.Space.Y, (ushort)tabAttributes.Space.Z, (ushort)tabAttributes.Space.W);
153 tabAttributes.Space = new Vector4(value.Start, value.End, value.Top, value.Bottom);
160 /// UnderLine view's size in Tab.
162 /// <since_tizen> 6 </since_tizen>
163 public Size UnderLineSize
167 return tabAttributes.UnderLineAttributes?.Size;
173 CreateUnderLineAttributes();
174 tabAttributes.UnderLineAttributes.Size = value;
181 /// UnderLine view's background in Tab.
183 /// <since_tizen> 6 </since_tizen>
184 public Color UnderLineBackgroundColor
188 return tabAttributes.UnderLineAttributes?.BackgroundColor?.All;
194 CreateUnderLineAttributes();
195 if (tabAttributes.UnderLineAttributes.BackgroundColor == null)
197 tabAttributes.UnderLineAttributes.BackgroundColor = new ColorSelector();
199 tabAttributes.UnderLineAttributes.BackgroundColor.All = value;
206 /// Text point size in Tab.
208 /// <since_tizen> 6 </since_tizen>
209 public float PointSize
213 return tabAttributes.TextAttributes?.PointSize?.All ?? 0;
217 CreateTextAttributes();
218 if (tabAttributes.TextAttributes.PointSize == null)
220 tabAttributes.TextAttributes.PointSize = new FloatSelector();
222 tabAttributes.TextAttributes.PointSize.All = value;
228 /// Text font family in Tab.
230 /// <since_tizen> 6 </since_tizen>
231 public string FontFamily
235 return tabAttributes.TextAttributes?.FontFamily;
239 CreateTextAttributes();
240 tabAttributes.TextAttributes.FontFamily = value;
246 /// Text color in Tab.
248 /// <since_tizen> 6 </since_tizen>
249 public Color TextColor
253 return tabAttributes.TextAttributes?.TextColor?.All;
257 CreateTextAttributes();
258 if (tabAttributes.TextAttributes.TextColor == null)
260 tabAttributes.TextAttributes.TextColor = new ColorSelector();
262 tabAttributes.TextAttributes.TextColor.All = value;
268 /// Text color selector in Tab.
270 /// <since_tizen> 6 </since_tizen>
271 public ColorSelector TextColorSelector
275 return tabAttributes.TextAttributes.TextColor;
281 CreateTextAttributes();
282 tabAttributes.TextAttributes.TextColor = value.Clone() as ColorSelector;
289 /// Add tab item by item data. The added item will be added to end of all items automatically.
291 /// <param name="itemData">Item data which will apply to tab item view.</param>
292 /// <since_tizen> 6 </since_tizen>
293 public void AddItem(TabItemData itemData)
295 AddItemByIndex(itemData, itemList.Count);
299 /// Insert tab item by item data. The inserted item will be added to the special position by index automatically.
301 /// <param name="itemData">Item data which will apply to tab item view.</param>
302 /// <param name="index">Position index where will be inserted.</param>
303 /// <since_tizen> 6 </since_tizen>
304 public void InsertItem(TabItemData itemData, int index)
306 AddItemByIndex(itemData, index);
310 /// Delete tab item by index.
312 /// <param name="itemIndex">Position index where will be deleted.</param>
313 /// <since_tizen> 6 </since_tizen>
314 public void DeleteItem(int itemIndex)
316 if(itemList == null || itemIndex < 0 || itemIndex >= itemList.Count)
321 if (curIndex > itemIndex || (curIndex == itemIndex && itemIndex == itemList.Count - 1))
326 Remove(itemList[itemIndex]);
327 itemList[itemIndex].Dispose();
328 itemList.RemoveAt(itemIndex);
334 /// Dispose Tab and all children on it.
336 /// <param name="type">Dispose type.</param>
337 /// <since_tizen> 6 </since_tizen>
338 protected override void Dispose(DisposeTypes type)
345 if (type == DisposeTypes.Explicit)
347 if(underlineAni != null)
349 if(underlineAni.State == Animation.States.Playing)
353 underlineAni.Dispose();
356 Utility.Dispose(underline);
359 for(int i = 0; i < itemList.Count; i++)
362 itemList[i].Dispose();
374 /// Update Tab by attributes.
376 /// <since_tizen> 6 </since_tizen>
377 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
378 [EditorBrowsable(EditorBrowsableState.Never)]
379 protected override void OnUpdate()
381 if (tabAttributes.UnderLineAttributes != null)
383 if (underline == null)
385 underline = new View()
387 PositionUsesPivotPoint = true,
388 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
389 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
392 CreateUnderLineAnimation();
394 ApplyAttributes(underline, tabAttributes.UnderLineAttributes);
397 if (tabAttributes.TextAttributes != null)
399 if (curIndex >= 0 && curIndex < itemList.Count)
401 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
409 /// Get Tab attribues.
411 /// <since_tizen> 6 </since_tizen>
412 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
413 [EditorBrowsable(EditorBrowsableState.Never)]
414 protected override Attributes GetAttributes()
416 return new TabAttributes();
420 /// Theme change callback when theme is changed, this callback will be trigger.
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 void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
427 TabAttributes tempAttributes = StyleManager.Instance.GetAttributes(style) as TabAttributes;
428 if (tempAttributes != null)
430 tempAttributes.UseTextNaturalSize = tabAttributes.UseTextNaturalSize; // keep IsNatureTextWidth as original
431 attributes = tabAttributes = tempAttributes;
437 /// Layout child in Tab and it can be override by user.
439 /// <since_tizen> 6 </since_tizen>
440 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
441 [EditorBrowsable(EditorBrowsableState.Never)]
442 protected virtual void LayoutChild()
444 if (tabAttributes == null || itemList == null)
448 int totalNum = itemList.Count;
454 int preX = (int)tabAttributes.Space.X;
456 int itemSpace = tabAttributes.ItemSpace;
458 if (LayoutDirection == ViewLayoutDirectionType.LTR)
460 if (tabAttributes.UseTextNaturalSize == true)
462 for (int i = 0; i < totalNum; i++)
464 preW = itemList[i].TextItem.NaturalSize2D.Width;
465 itemList[i].Position2D.X = preX;
466 itemList[i].Size2D.Width = preW;
467 preX = itemList[i].Position2D.X + preW + itemSpace;
468 itemList[i].Index = i;
473 preW = (Size2D.Width - (int)tabAttributes.Space.X - (int)tabAttributes.Space.Y) / totalNum;
474 for (int i = 0; i < totalNum; i++)
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;
485 preX = (int)tabAttributes.Space.Y;
486 if (tabAttributes.UseTextNaturalSize == true)
488 int w = Size2D.Width;
489 for (int i = 0; i < totalNum; i++)
491 preW = (itemList[i].TextItem.NaturalSize2D != null ? itemList[i].TextItem.NaturalSize2D.Width : 0);
492 itemList[i].Position2D.X = w - preW - preX;
493 itemList[i].Size2D.Width = preW;
494 preX = w - itemList[i].Position2D.X + itemSpace;
495 itemList[i].Index = i;
500 preW = (Size2D.Width - (int)tabAttributes.Space.X - (int)tabAttributes.Space.Y) / totalNum;
501 for (int i = totalNum - 1; i >= 0; i--)
503 itemList[i].Position2D.X = preX;
504 itemList[i].Size2D.Width = preW;
505 preX = itemList[i].Position2D.X + preW + itemSpace;
506 itemList[i].Index = i;
510 UpdateUnderLinePos();
513 private void Initialize()
515 tabAttributes = attributes as TabAttributes;
516 if (tabAttributes == null)
518 throw new Exception("Tab attribute parse error.");
521 ApplyAttributes(this, tabAttributes);
522 LayoutDirectionChanged += OnLayoutDirectionChanged;
525 private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
530 private void AddItemByIndex(TabItemData itemData, int index)
533 int topSpace = (int)tabAttributes.Space.Z;
534 if (tabAttributes.UnderLineAttributes != null && tabAttributes.UnderLineAttributes.Size != null)
536 h = (int)tabAttributes.UnderLineAttributes.Size.Height;
538 Tab.TabItem item = new TabItem();
539 ApplyAttributes(item.TextItem, tabAttributes.TextAttributes);
540 item.TextItem.Text = itemData.Text;
541 item.Size2D.Height = Size2D.Height - h - topSpace;
542 item.Position2D.Y = topSpace;
543 item.TouchEvent += ItemTouchEvent;
546 if(index >= itemList.Count)
552 itemList.Insert(index, item);
558 private void UpdateItems()
561 if (itemList != null && curIndex >= 0 && curIndex < itemList.Count)
563 itemList[curIndex].State = ControlStates.Selected;
564 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
565 UpdateUnderLinePos();
569 if (underline != null)
576 private void CreateUnderLineAttributes()
578 if (tabAttributes.UnderLineAttributes == null)
580 tabAttributes.UnderLineAttributes = new ViewAttributes()
582 PositionUsesPivotPoint = true,
583 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
584 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
589 private void CreateTextAttributes()
591 if (tabAttributes.TextAttributes == null)
593 tabAttributes.TextAttributes = new TextAttributes()
595 PositionUsesPivotPoint = true,
596 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
597 PivotPoint = Tizen.NUI.PivotPoint.Center,
598 HorizontalAlignment = HorizontalAlignment.Center,
599 VerticalAlignment = VerticalAlignment.Center,
600 WidthResizePolicy = ResizePolicyType.FillToParent,
601 HeightResizePolicy = ResizePolicyType.FillToParent
606 private void CreateUnderLineAnimation()
608 if (underlineAni == null)
610 underlineAni = new Animation(aniTime);
614 private void UpdateUnderLinePos()
616 if (underline == null || tabAttributes.UnderLineAttributes == null || tabAttributes.UnderLineAttributes.Size == null
617 || itemList == null || itemList.Count <= 0)
622 tabAttributes.UnderLineAttributes.Size.Width = itemList[curIndex].Size2D.Width;
624 underline.Size2D = new Size2D(itemList[curIndex].Size2D.Width, (int)tabAttributes.UnderLineAttributes.Size.Height);
625 underline.BackgroundColor = tabAttributes.UnderLineAttributes.BackgroundColor.All;
628 CreateUnderLineAnimation();
629 if (underlineAni.State == Animation.States.Playing)
633 underlineAni.Clear();
634 underlineAni.AnimateTo(underline, "PositionX", itemList[curIndex].Position2D.X);
639 underline.Position2D.X = itemList[curIndex].Position2D.X;
640 isNeedAnimation = true;
646 private void UpdateSelectedItem(TabItem item)
648 if(item == null || curIndex == item.Index)
653 ItemChangedEventArgs e = new ItemChangedEventArgs
655 PreviousIndex = curIndex,
656 CurrentIndex = item.Index
658 ItemChangedEvent?.Invoke(this, e);
660 itemList[curIndex].State = ControlStates.Normal;
661 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
662 curIndex = item.Index;
663 itemList[curIndex].State = ControlStates.Selected;
664 itemList[curIndex].UpdateItemText(tabAttributes.TextAttributes);
666 UpdateUnderLinePos();
669 private bool ItemTouchEvent(object source, TouchEventArgs e)
671 TabItem item = source as TabItem;
676 PointStateType state = e.Touch.GetState(0);
677 if (state == PointStateType.Up)
679 UpdateSelectedItem(item);
685 internal class TabItem : Control
687 public TabItem() : base()
689 TextItem = new TextLabel()
691 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
692 PivotPoint = Tizen.NUI.PivotPoint.Center,
693 PositionUsesPivotPoint = true,
694 WidthResizePolicy = ResizePolicyType.FillToParent,
695 HeightResizePolicy = ResizePolicyType.FillToParent,
696 HorizontalAlignment = HorizontalAlignment.Center,
697 VerticalAlignment = VerticalAlignment.Center
706 return TextItem.Text;
710 TextItem.Text = value;
720 internal TextLabel TextItem
726 protected override void Dispose(DisposeTypes type)
733 if (type == DisposeTypes.Explicit)
735 if (TextItem != null)
746 protected override Attributes GetAttributes()
751 internal void UpdateItemText(TextAttributes attrs)
753 ApplyAttributes(TextItem, attrs);
758 /// TabItemData is a class to record all data which will be applied to Tab item.
760 /// <since_tizen> 6 </since_tizen>
761 public class TabItemData
764 /// Text string in tab item view.
766 /// <since_tizen> 6 </since_tizen>
775 /// ItemChangedEventArgs is a class to record item change event arguments which will sent to user.
777 /// <since_tizen> 6 </since_tizen>
778 public class ItemChangedEventArgs : EventArgs
780 /// <summary> Previous selected index of Tab </summary>
781 /// <since_tizen> 6 </since_tizen>
782 public int PreviousIndex;
783 /// <summary> Current selected index of Tab </summary>
784 /// <since_tizen> 6 </since_tizen>
785 public int CurrentIndex;