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;
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 style.
63 /// <param name="style">Create Tab by style 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(TabStyle style) : base(style)
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;
78 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public new TabStyle Style => ViewStyle as TabStyle;
83 /// Selected item's index in Tab.
85 /// <since_tizen> 6 </since_tizen>
86 public int SelectedItemIndex
94 if (value < itemList.Count)
96 UpdateSelectedItem(itemList[value]);
102 /// Flag to decide if TabItem is adjusted by text's natural width.
103 /// 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.
105 /// <since_tizen> 6 </since_tizen>
106 public bool UseTextNaturalSize
110 return Style.UseTextNaturalSize;
114 Style.UseTextNaturalSize = value;
120 /// Gap between items.
122 /// <since_tizen> 6 </since_tizen>
127 return Style.ItemSpace;
131 Style.ItemSpace = value;
137 /// Space in Tab. Sequence as Left, Right, Top, Bottom
139 /// <since_tizen> 6 </since_tizen>
153 /// Item paddings in Tab. Sequence as Left, Right, Top, Bottom
155 /// <since_tizen> 6 </since_tizen>
156 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
157 [EditorBrowsable(EditorBrowsableState.Never)]
158 public Extents ItemPadding
168 Style.ItemPadding.CopyFrom(value);
172 space = new Extents((ushort start, ushort end, ushort top, ushort bottom) =>
174 Style.ItemPadding.Start = start;
175 Style.ItemPadding.End = end;
176 Style.ItemPadding.Top = top;
177 Style.ItemPadding.Bottom = bottom;
179 }, value.Start, value.End, value.Top, value.Bottom);
183 space.CopyFrom(value);
192 /// UnderLine view's size in Tab.
194 /// <since_tizen> 6 </since_tizen>
195 public Size UnderLineSize
199 return Style.UnderLine?.Size;
205 //CreateUnderLineAttributes();
206 Style.UnderLine.Size = value;
213 /// UnderLine view's background in Tab.
215 /// <since_tizen> 6 </since_tizen>
216 public Color UnderLineBackgroundColor
220 return Style.UnderLine?.BackgroundColor?.All;
226 //CreateUnderLineAttributes();
227 if (Style.UnderLine.BackgroundColor == null)
229 Style.UnderLine.BackgroundColor = new ColorSelector();
231 if (Style.UnderLine.BackgroundColor != null)
233 Style.UnderLine.BackgroundColor.All = value;
241 /// Text point size in Tab.
243 /// <since_tizen> 6 </since_tizen>
244 public float PointSize
248 return Style.Text?.PointSize?.All ?? 0;
252 //CreateTextAttributes();
253 if (Style.Text.PointSize == null)
255 Style.Text.PointSize = new FloatSelector();
257 if (Style.Text.PointSize != null)
259 Style.Text.PointSize.All = value;
266 /// Text font family in Tab.
268 /// <since_tizen> 6 </since_tizen>
269 public string FontFamily
273 return Style.Text?.FontFamily.All;
277 //CreateTextAttributes();
278 Style.Text.FontFamily.All = value;
284 /// Text color in Tab.
286 /// <since_tizen> 6 </since_tizen>
287 public Color TextColor
291 return Style.Text?.TextColor?.All;
295 //CreateTextAttributes();
296 if (Style.Text.TextColor == null)
298 Style.Text.TextColor = new ColorSelector();
300 if (Style.Text.TextColor != null)
302 Style.Text.TextColor.All = value;
308 private ColorSelector textColorSelector = new ColorSelector();
310 /// Text color selector in Tab.
312 /// <since_tizen> 6 </since_tizen>
313 public ColorSelector TextColorSelector
317 return textColorSelector;
321 textColorSelector.Clone(value);
327 /// Add tab item by item data. The added item will be added to end of all items automatically.
329 /// <param name="itemData">Item data which will apply to tab item view.</param>
330 /// <since_tizen> 6 </since_tizen>
331 public void AddItem(TabItemData itemData)
333 AddItemByIndex(itemData, itemList.Count);
337 /// Insert tab item by item data. The inserted item will be added to the special position by index automatically.
339 /// <param name="itemData">Item data which will apply to tab item view.</param>
340 /// <param name="index">Position index where will be inserted.</param>
341 /// <since_tizen> 6 </since_tizen>
342 public void InsertItem(TabItemData itemData, int index)
344 AddItemByIndex(itemData, index);
348 /// Delete tab item by index.
350 /// <param name="itemIndex">Position index where will be deleted.</param>
351 /// <since_tizen> 6 </since_tizen>
352 public void DeleteItem(int itemIndex)
354 if(itemList == null || itemIndex < 0 || itemIndex >= itemList.Count)
359 if (curIndex > itemIndex || (curIndex == itemIndex && itemIndex == itemList.Count - 1))
364 Remove(itemList[itemIndex]);
365 itemList[itemIndex].Dispose();
366 itemList.RemoveAt(itemIndex);
371 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
372 [EditorBrowsable(EditorBrowsableState.Never)]
373 public override void ApplyStyle(ViewStyle viewStyle)
375 base.ApplyStyle(viewStyle);
377 TabStyle tabStyle = viewStyle as TabStyle;
379 if (null != tabStyle)
381 if (null == underline)
383 underline = new View()
385 PositionUsesPivotPoint = true,
386 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
387 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
390 CreateUnderLineAnimation();
393 underline.ApplyStyle(Style.UnderLine);
398 /// Dispose Tab and all children on it.
400 /// <param name="type">Dispose type.</param>
401 /// <since_tizen> 6 </since_tizen>
402 protected override void Dispose(DisposeTypes type)
409 if (type == DisposeTypes.Explicit)
411 if(underlineAni != null)
413 if(underlineAni.State == Animation.States.Playing)
417 underlineAni.Dispose();
420 Utility.Dispose(underline);
423 for(int i = 0; i < itemList.Count; i++)
426 itemList[i].Dispose();
438 /// Update Tab by attributes.
440 /// <since_tizen> 6 </since_tizen>
441 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
442 [EditorBrowsable(EditorBrowsableState.Never)]
443 protected override void OnUpdate()
449 /// Get Tab attribues.
451 /// <since_tizen> 6 </since_tizen>
452 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
453 [EditorBrowsable(EditorBrowsableState.Never)]
454 protected override ViewStyle GetViewStyle()
456 return new TabStyle();
460 /// Theme change callback when theme is changed, this callback will be trigger.
462 /// <since_tizen> 6 </since_tizen>
463 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
464 [EditorBrowsable(EditorBrowsableState.Never)]
465 protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
467 TabStyle tempAttributes = StyleManager.Instance.GetAttributes(style) as TabStyle;
468 if (tempAttributes != null)
470 Style.CopyFrom(tempAttributes);
475 /// Layout child in Tab and it can be override by user.
477 /// <since_tizen> 6 </since_tizen>
478 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
479 [EditorBrowsable(EditorBrowsableState.Never)]
480 protected virtual void LayoutChild()
482 if (itemList == null)
487 int totalNum = itemList.Count;
493 int preX = (int)Style.ItemPadding.Start;
495 int itemSpace = Style.ItemSpace;
497 if (LayoutDirection == ViewLayoutDirectionType.LTR)
499 if (Style.UseTextNaturalSize == true)
501 for (int i = 0; i < totalNum; i++)
503 preW = (itemList[i].NaturalSize2D != null ? itemList[i].NaturalSize2D.Width : 0);
504 itemList[i].Position2D.X = preX;
505 itemList[i].Size2D.Width = preW;
506 preX = itemList[i].Position2D.X + preW + itemSpace;
507 itemList[i].Index = i;
512 preW = (Size2D.Width - (int)Style.ItemPadding.Start - (int)Style.ItemPadding.End) / totalNum;
513 for (int i = 0; i < totalNum; i++)
515 itemList[i].Position2D.X = preX;
516 itemList[i].Size2D.Width = preW;
517 preX = itemList[i].Position2D.X + preW + itemSpace;
518 itemList[i].Index = i;
524 preX = (int)Style.ItemPadding.End;
525 if (Style.UseTextNaturalSize == true)
527 int w = Size2D.Width;
528 for (int i = 0; i < totalNum; i++)
530 preW = (itemList[i].NaturalSize2D != null ? itemList[i].NaturalSize2D.Width : 0);
531 itemList[i].Position2D.X = w - preW - preX;
532 itemList[i].Size2D.Width = preW;
533 preX = w - itemList[i].Position2D.X + itemSpace;
534 itemList[i].Index = i;
539 preW = (Size2D.Width - (int)Style.ItemPadding.Start - (int)Style.ItemPadding.End) / totalNum;
540 for (int i = totalNum - 1; i >= 0; i--)
542 itemList[i].Position2D.X = preX;
543 itemList[i].Size2D.Width = preW;
544 preX = itemList[i].Position2D.X + preW + itemSpace;
545 itemList[i].Index = i;
549 UpdateUnderLinePos();
552 private void Initialize()
554 LayoutDirectionChanged += OnLayoutDirectionChanged;
557 private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
562 private void AddItemByIndex(TabItemData itemData, int index)
565 int topSpace = (int)Style.ItemPadding.Top;
566 if (Style.UnderLine != null && Style.UnderLine.Size != null)
568 h = (int)Style.UnderLine.Size.Height;
571 Tab.TabItem item = new TabItem();
572 item.TextItem.ApplyStyle(Style.Text);
574 item.Text = itemData.Text;
575 item.Size2D.Height = Size2D.Height - h - topSpace;
576 item.Position2D.Y = topSpace;
577 item.TouchEvent += ItemTouchEvent;
580 if (index >= itemList.Count)
586 itemList.Insert(index, item);
592 private void UpdateItems()
595 if (itemList != null && curIndex >= 0 && curIndex < itemList.Count)
597 itemList[curIndex].ControlState = ControlStates.Selected;
598 UpdateUnderLinePos();
602 if (underline != null)
609 private void CreateUnderLineAttributes()
611 if (Style.UnderLine == null)
613 Style.UnderLine = new ViewStyle()
615 PositionUsesPivotPoint = true,
616 ParentOrigin = Tizen.NUI.ParentOrigin.BottomLeft,
617 PivotPoint = Tizen.NUI.PivotPoint.BottomLeft,
622 private void CreateUnderLineAnimation()
624 if (underlineAni == null)
626 underlineAni = new Animation(aniTime);
630 private void UpdateUnderLinePos()
632 if (underline == null || Style.UnderLine == null || Style.UnderLine.Size == null
633 || itemList == null || itemList.Count <= 0)
638 Style.UnderLine.Size.Width = itemList[curIndex].Size2D.Width;
640 underline.Size2D = new Size2D(itemList[curIndex].Size2D.Width, (int)Style.UnderLine.Size.Height);
641 underline.BackgroundColor = Style.UnderLine.BackgroundColor.All;
644 CreateUnderLineAnimation();
645 if (underlineAni.State == Animation.States.Playing)
649 underlineAni.Clear();
650 underlineAni.AnimateTo(underline, "PositionX", itemList[curIndex].Position2D.X);
655 underline.Position2D.X = itemList[curIndex].Position2D.X;
656 isNeedAnimation = true;
662 private void UpdateSelectedItem(TabItem item)
664 if(item == null || curIndex == item.Index)
669 ItemChangedEventArgs e = new ItemChangedEventArgs
671 PreviousIndex = curIndex,
672 CurrentIndex = item.Index
674 ItemChangedEvent?.Invoke(this, e);
676 itemList[curIndex].ControlState = ControlStates.Normal;
677 curIndex = item.Index;
678 itemList[curIndex].ControlState = ControlStates.Selected;
680 UpdateUnderLinePos();
683 private bool ItemTouchEvent(object source, TouchEventArgs e)
685 TabItem item = source as TabItem;
690 PointStateType state = e.Touch.GetState(0);
691 if (state == PointStateType.Up)
693 UpdateSelectedItem(item);
699 internal class TabItem : View
701 public TabItem() : base()
703 TextItem = new TextLabel()
705 ParentOrigin = Tizen.NUI.ParentOrigin.Center,
706 PivotPoint = Tizen.NUI.PivotPoint.Center,
707 PositionUsesPivotPoint = true,
708 WidthResizePolicy = ResizePolicyType.FillToParent,
709 HeightResizePolicy = ResizePolicyType.FillToParent,
710 HorizontalAlignment = HorizontalAlignment.Center,
711 VerticalAlignment = VerticalAlignment.Center
726 return TextItem.Text;
730 TextItem.Text = value;
734 internal TextLabel TextItem
742 /// TabItemData is a class to record all data which will be applied to Tab item.
744 /// <since_tizen> 6 </since_tizen>
745 public class TabItemData
748 /// Text string in tab item view.
750 /// <since_tizen> 6 </since_tizen>
759 /// ItemChangedEventArgs is a class to record item change event arguments which will sent to user.
761 /// <since_tizen> 6 </since_tizen>
762 public class ItemChangedEventArgs : EventArgs
764 /// <summary> Previous selected index of Tab </summary>
765 /// <since_tizen> 6 </since_tizen>
766 public int PreviousIndex;
767 /// <summary> Current selected index of Tab </summary>
768 /// <since_tizen> 6 </since_tizen>
769 public int CurrentIndex;