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 Animation underlineAni = null;
36 private bool isNeedAnimation = false;
37 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 style.
64 /// <param name="style">Create Tab by style 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(TabStyle style) : base(style)
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;
79 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 public new TabStyle Style => ViewStyle as TabStyle;
84 /// Selected item's index in Tab.
86 /// <since_tizen> 6 </since_tizen>
87 public int SelectedItemIndex
95 if (value < itemList.Count)
97 UpdateSelectedItem(itemList[value]);
103 /// Flag to decide if TabItem is adjusted by text's natural width.
104 /// 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.
106 /// <since_tizen> 6 </since_tizen>
107 public bool UseTextNaturalSize
111 return Style?.UseTextNaturalSize ?? false;
117 Style.UseTextNaturalSize = value;
124 /// Gap between items.
126 /// <since_tizen> 6 </since_tizen>
131 return Style?.ItemSpace ?? 0;
137 Style.ItemSpace = value;
144 /// Space in Tab. Sequence as Left, Right, Top, Bottom
146 /// <since_tizen> 6 </since_tizen>
160 /// Item paddings in Tab. Sequence as Left, Right, Top, Bottom
162 /// <since_tizen> 6 </since_tizen>
163 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
164 [EditorBrowsable(EditorBrowsableState.Never)]
165 public Extents ItemPadding
173 if(null != value && null != Style?.ItemPadding)
175 Style.ItemPadding.CopyFrom(value);
179 space = new Extents((ushort start, ushort end, ushort top, ushort bottom) =>
181 Style.ItemPadding.Start = start;
182 Style.ItemPadding.End = end;
183 Style.ItemPadding.Top = top;
184 Style.ItemPadding.Bottom = bottom;
186 }, value.Start, value.End, value.Top, value.Bottom);
190 space.CopyFrom(value);
199 /// UnderLine view's size in Tab.
201 /// <since_tizen> 6 </since_tizen>
202 public Size UnderLineSize
206 return Style?.UnderLine?.Size;
210 if (null != Style?.UnderLine)
212 Style.UnderLine.Size = value;
218 /// UnderLine view's background in Tab.
220 /// <since_tizen> 6 </since_tizen>
221 public Color UnderLineBackgroundColor
225 return Style?.UnderLine?.BackgroundColor?.All;
229 if (null != Style?.UnderLine)
231 Style.UnderLine.BackgroundColor = value;
237 /// Text point size in Tab.
239 /// <since_tizen> 6 </since_tizen>
240 public float PointSize
244 return Style?.Text?.PointSize?.All ?? 0;
248 if (null != Style?.Text)
250 Style.Text.PointSize = value;
256 /// Text font family in Tab.
258 /// <since_tizen> 6 </since_tizen>
259 public string FontFamily
263 return Style?.Text?.FontFamily?.All;
267 if (null != Style?.Text)
269 Style.Text.FontFamily = value;
275 /// Text color in Tab.
277 /// <since_tizen> 6 </since_tizen>
278 public Color TextColor
282 return Style?.Text?.TextColor?.All;
286 if (null != Style?.Text)
288 Style.Text.TextColor = value;
293 private ColorSelector textColorSelector = new ColorSelector();
295 /// Text color selector in Tab.
297 /// <since_tizen> 6 </since_tizen>
298 public ColorSelector TextColorSelector
302 return textColorSelector;
306 textColorSelector.Clone(value);
311 /// Add tab item by item data. The added item will be added to end of all items automatically.
313 /// <param name="itemData">Item data which will apply to tab item view.</param>
314 /// <since_tizen> 6 </since_tizen>
315 public void AddItem(TabItemData itemData)
317 AddItemByIndex(itemData, itemList.Count);
321 /// Insert tab item by item data. The inserted item will be added to the special position by index automatically.
323 /// <param name="itemData">Item data which will apply to tab item view.</param>
324 /// <param name="index">Position index where will be inserted.</param>
325 /// <since_tizen> 6 </since_tizen>
326 public void InsertItem(TabItemData itemData, int index)
328 AddItemByIndex(itemData, index);
332 /// Delete tab item by index.
334 /// <param name="itemIndex">Position index where will be deleted.</param>
335 /// <since_tizen> 6 </since_tizen>
336 public void DeleteItem(int itemIndex)
338 if(itemList == null || itemIndex < 0 || itemIndex >= itemList.Count)
343 if (curIndex > itemIndex || (curIndex == itemIndex && itemIndex == itemList.Count - 1))
348 Remove(itemList[itemIndex]);
349 itemList[itemIndex].Dispose();
350 itemList.RemoveAt(itemIndex);
355 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
356 [EditorBrowsable(EditorBrowsableState.Never)]
357 public override void ApplyStyle(ViewStyle viewStyle)
359 base.ApplyStyle(viewStyle);
361 TabStyle tabStyle = viewStyle as TabStyle;
363 if (null != tabStyle)
365 if (null == underline)
367 underline = new View()
369 PositionUsesPivotPoint = true,
370 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
371 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
374 CreateUnderLineAnimation();
377 underline.ApplyStyle(Style.UnderLine);
382 /// Dispose Tab and all children on it.
384 /// <param name="type">Dispose type.</param>
385 /// <since_tizen> 6 </since_tizen>
386 protected override void Dispose(DisposeTypes type)
393 if (type == DisposeTypes.Explicit)
395 if(underlineAni != null)
397 if(underlineAni.State == Animation.States.Playing)
401 underlineAni.Dispose();
404 Utility.Dispose(underline);
407 for(int i = 0; i < itemList.Count; i++)
410 itemList[i].Dispose();
422 /// Update Tab by attributes.
424 /// <since_tizen> 6 </since_tizen>
425 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
426 [EditorBrowsable(EditorBrowsableState.Never)]
427 protected override void OnUpdate()
433 /// Get Tab attribues.
435 /// <since_tizen> 6 </since_tizen>
436 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
437 [EditorBrowsable(EditorBrowsableState.Never)]
438 protected override ViewStyle GetViewStyle()
440 return new TabStyle();
444 /// Theme change callback when theme is changed, this callback will be trigger.
446 /// <since_tizen> 6 </since_tizen>
447 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
448 [EditorBrowsable(EditorBrowsableState.Never)]
449 protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
451 TabStyle tempAttributes = StyleManager.Instance.GetViewStyle(style) as TabStyle;
452 if (tempAttributes != null)
454 Style.CopyFrom(tempAttributes);
459 /// Layout child in Tab and it can be override by user.
461 /// <since_tizen> 6 </since_tizen>
462 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
463 [EditorBrowsable(EditorBrowsableState.Never)]
464 protected virtual void LayoutChild()
466 if (itemList == null)
471 int totalNum = itemList.Count;
477 int preX = (int)Style.ItemPadding.Start;
479 int itemSpace = Style.ItemSpace;
481 if (LayoutDirection == ViewLayoutDirectionType.LTR)
483 if (Style.UseTextNaturalSize == true)
485 for (int i = 0; i < totalNum; i++)
487 preW = (itemList[i].TextItem.NaturalSize2D != null ? itemList[i].TextItem.NaturalSize2D.Width : 0);
488 itemList[i].Position2D.X = preX;
489 itemList[i].Size2D.Width = preW;
490 preX = itemList[i].Position2D.X + preW + itemSpace;
491 itemList[i].Index = i;
496 preW = (Size2D.Width - (int)Style.ItemPadding.Start - (int)Style.ItemPadding.End) / totalNum;
497 for (int i = 0; i < totalNum; i++)
499 itemList[i].Position2D.X = preX;
500 itemList[i].Size2D.Width = preW;
501 preX = itemList[i].Position2D.X + preW + itemSpace;
502 itemList[i].Index = i;
508 preX = (int)Style.ItemPadding.End;
509 if (Style.UseTextNaturalSize == true)
511 int w = Size2D.Width;
512 for (int i = 0; i < totalNum; i++)
514 preW = (itemList[i].NaturalSize2D != null ? itemList[i].NaturalSize2D.Width : 0);
515 itemList[i].Position2D.X = w - preW - preX;
516 itemList[i].Size2D.Width = preW;
517 preX = w - itemList[i].Position2D.X + itemSpace;
518 itemList[i].Index = i;
523 preW = (Size2D.Width - (int)Style.ItemPadding.Start - (int)Style.ItemPadding.End) / totalNum;
524 for (int i = totalNum - 1; i >= 0; i--)
526 itemList[i].Position2D.X = preX;
527 itemList[i].Size2D.Width = preW;
528 preX = itemList[i].Position2D.X + preW + itemSpace;
529 itemList[i].Index = i;
533 UpdateUnderLinePos();
536 private void Initialize()
538 LayoutDirectionChanged += OnLayoutDirectionChanged;
541 private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
546 private void AddItemByIndex(TabItemData itemData, int index)
548 if (null == itemData) return;
550 int topSpace = (int)Style.ItemPadding.Top;
551 if (Style.UnderLine != null && Style.UnderLine.Size != null)
553 h = (int)Style.UnderLine.Size.Height;
556 Tab.TabItem item = new TabItem();
557 item.TextItem.ApplyStyle(Style.Text);
559 item.Text = itemData.Text;
560 item.Size2D.Height = Size2D.Height - h - topSpace;
561 item.Position2D.Y = topSpace;
562 item.TouchEvent += ItemTouchEvent;
565 if (index >= itemList.Count)
571 itemList.Insert(index, item);
577 private void UpdateItems()
580 if (itemList != null && curIndex >= 0 && curIndex < itemList.Count)
582 itemList[curIndex].ControlState = ControlStates.Selected;
583 UpdateUnderLinePos();
587 if (underline != null)
594 private void CreateUnderLineAttributes()
596 if (Style.UnderLine == null)
598 Style.UnderLine = new ViewStyle()
600 PositionUsesPivotPoint = true,
601 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
602 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
607 private void CreateUnderLineAnimation()
609 if (underlineAni == null)
611 underlineAni = new Animation(aniTime);
615 private void UpdateUnderLinePos()
617 if (underline == null || Style.UnderLine == null || Style.UnderLine.Size == null
618 || itemList == null || itemList.Count <= 0)
623 Style.UnderLine.Size.Width = itemList[curIndex].Size2D.Width;
625 underline.Size2D = new Size2D(itemList[curIndex].Size2D.Width, (int)Style.UnderLine.Size.Height);
626 underline.BackgroundColor = Style.UnderLine.BackgroundColor.All;
629 CreateUnderLineAnimation();
630 if (underlineAni.State == Animation.States.Playing)
634 underlineAni.Clear();
635 underlineAni.AnimateTo(underline, "PositionX", itemList[curIndex].Position2D.X);
640 underline.Position2D.X = itemList[curIndex].Position2D.X;
641 isNeedAnimation = true;
647 private void UpdateSelectedItem(TabItem item)
649 if(item == null || curIndex == item.Index)
654 ItemChangedEventArgs e = new ItemChangedEventArgs
656 PreviousIndex = curIndex,
657 CurrentIndex = item.Index
659 ItemChangedEvent?.Invoke(this, e);
661 itemList[curIndex].ControlState = ControlStates.Normal;
662 curIndex = item.Index;
663 itemList[curIndex].ControlState = ControlStates.Selected;
665 UpdateUnderLinePos();
668 private bool ItemTouchEvent(object source, TouchEventArgs e)
670 TabItem item = source as TabItem;
675 PointStateType state = e.Touch.GetState(0);
676 if (state == PointStateType.Up)
678 UpdateSelectedItem(item);
684 internal class TabItem : View
686 public TabItem() : base()
688 TextItem = new TextLabel()
690 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
691 PivotPoint = Tizen.NUI.PivotPoint.Center,
692 PositionUsesPivotPoint = true,
693 WidthResizePolicy = ResizePolicyType.FillToParent,
694 HeightResizePolicy = ResizePolicyType.FillToParent,
695 HorizontalAlignment = HorizontalAlignment.Center,
696 VerticalAlignment = VerticalAlignment.Center
711 return TextItem.Text;
715 TextItem.Text = value;
719 internal TextLabel TextItem
727 /// TabItemData is a class to record all data which will be applied to Tab item.
729 /// <since_tizen> 6 </since_tizen>
730 public class TabItemData
733 /// Text string in tab item view.
735 /// <since_tizen> 6 </since_tizen>
744 /// ItemChangedEventArgs is a class to record item change event arguments which will sent to user.
746 /// <since_tizen> 6 </since_tizen>
747 public class ItemChangedEventArgs : EventArgs
749 /// <summary> Previous selected index of Tab </summary>
750 /// <since_tizen> 6 </since_tizen>
751 public int PreviousIndex;
752 /// <summary> Current selected index of Tab </summary>
753 /// <since_tizen> 6 </since_tizen>
754 public int CurrentIndex;