[NUI] Add TabButtonStyle class with the latest TabButton UX (#2780)
authorJaehyun Cho <jaehyun0cho@gmail.com>
Wed, 31 Mar 2021 07:38:59 +0000 (16:38 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Thu, 1 Apr 2021 01:07:37 +0000 (10:07 +0900)
To apply the latest TabButton UX, TabButtonStyle class is added.

TabButtonStyle.TopLine and TabButtonStyle.BottomLine are displayed when
TabButton is pressed or selected.

Co-authored-by: Jaehyun Cho <jae_hyun.cho@samsung.com>
src/Tizen.NUI.Components/Controls/TabBar.cs
src/Tizen.NUI.Components/Controls/TabButton.cs
src/Tizen.NUI.Components/Style/TabButtonStyle.cs [new file with mode: 0755]
src/Tizen.NUI.Components/Theme/DefaultTheme.cs
src/Tizen.NUI.Components/Theme/DefaultThemeCommon.cs

index 8f6fa4c..ee69ed5 100755 (executable)
@@ -55,9 +55,6 @@ namespace Tizen.NUI.Components
 
         private TabButtonGroup tabButtonGroup;
 
-        //TODO: This tab button height should be implemented in TabBar style.
-        private float tabButtonHeight = 72.0f;
-
         /// <summary>
         /// Creates a new instance of TabBar.
         /// </summary>
@@ -209,9 +206,9 @@ namespace Tizen.NUI.Components
 
             foreach (TabButton tabButton in tabButtons)
             {
-                if ((tabButton.Size.Width != tabButtonWidth) || (tabButton.Size.Height != tabButtonHeight))
+                if (tabButton.Size.Width != tabButtonWidth)
                 {
-                    tabButton.Size = new Size(tabButtonWidth, tabButtonHeight);
+                    tabButton.Size = new Size(tabButtonWidth, tabButton.Size.Height);
                 }
             }
         }
index 77ab394..0555e29 100755 (executable)
@@ -28,13 +28,71 @@ namespace Tizen.NUI.Components
     {
         private bool selectedAgain = false;
 
+        private TabButtonStyle tabButtonStyle = null;
+
+        private bool styleApplied = false;
+
+        private View topLine = null;
+        private View bottomLine = null; // Visible only if TabButton is selected or pressed.
+
         /// <summary>
         /// Creates a new instance of TabButton.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public TabButton()
         {
-            GridLayout.SetHorizontalStretch(this, GridLayout.StretchFlags.ExpandAndFill);
+            Initialize();
+        }
+
+        /// <summary>
+        /// Creates a new instance of TabButton.
+        /// </summary>
+        /// <param name="style">Creates TabButton by special style defined in UX.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TabButton(string style) : base(style)
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// Creates a new instance of TabButton.
+        /// </summary>
+        /// <param name="tabButtonStyle">Creates TabButton by style customized by user.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TabButton(TabButtonStyle tabButtonStyle) : base(tabButtonStyle)
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// Applies style to TabButton.
+        /// </summary>
+        /// <param name="viewStyle">The style to apply.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void ApplyStyle(ViewStyle viewStyle)
+        {
+            styleApplied = false;
+
+            base.ApplyStyle(viewStyle);
+
+            tabButtonStyle = viewStyle as TabButtonStyle;
+
+            //Apply TopLine style.
+            if (tabButtonStyle?.TopLine != null)
+            {
+                topLine?.ApplyStyle(tabButtonStyle.TopLine);
+            }
+
+            //Apply BottomLine style.
+            if (tabButtonStyle?.BottomLine != null)
+            {
+                bottomLine?.ApplyStyle(tabButtonStyle.BottomLine);
+            }
+
+            styleApplied = true;
+
+            //Calculate children's sizes and positions based on padding sizes.
+            LayoutItems();
         }
 
         /// <inheritdoc/>
@@ -68,6 +126,44 @@ namespace Tizen.NUI.Components
             return ret;
         }
 
+        /// <summary>
+        /// Dispose TabButton and all children on it.
+        /// </summary>
+        /// <param name="type">Dispose type.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (disposed)
+            {
+                return;
+            }
+
+            if (type == DisposeTypes.Explicit)
+            {
+                if (topLine != null)
+                {
+                    Utility.Dispose(topLine);
+                }
+
+                if (bottomLine != null)
+                {
+                    Utility.Dispose(bottomLine);
+                }
+            }
+
+            base.Dispose(type);
+        }
+
+        /// <summary>
+        /// Gets TabButton style.
+        /// </summary>
+        /// <returns>The default TabButton style.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override ViewStyle CreateViewStyle()
+        {
+            return new TabButtonStyle();
+        }
+
         /// <inheritdoc/>
         [EditorBrowsable(EditorBrowsableState.Never)]
         protected override bool HandleControlStateOnTouch(Touch touch)
@@ -121,5 +217,138 @@ namespace Tizen.NUI.Components
                 base.OnControlStateChanged(controlStateChangedInfo);
             }
         }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void OnUpdate()
+        {
+            base.OnUpdate();
+            LayoutItems();
+        }
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void LayoutItems()
+        {
+            if (styleApplied == false)
+            {
+                return;
+            }
+
+            if ((Icon == null) && (TextLabel == null))
+            {
+                return;
+            }
+
+            // Icon is added in Button.LayoutItems().
+            if ((Icon != null) && (Children.Contains(Icon) == false))
+            {
+                Add(Icon);
+            }
+
+            // TextLabel is added in Button.LayoutItems().
+            if ((TextLabel != null) && (Children.Contains(TextLabel) == false))
+            {
+                Add(TextLabel);
+            }
+
+            // FIXME: set Selector<Extents> to padding
+            var padding = new Extents(40, 40, 24, 24);
+            var iconPadding = IconPadding;
+            var textPadding = TextPadding;
+
+            // Calculate size of TextLabel.
+            if (TextLabel != null)
+            {
+                // TODO: Other orientation cases are not implemented yet.
+                if ((IconRelativeOrientation == IconOrientation.Left) || (IconRelativeOrientation == IconOrientation.Right))
+                {
+                    var naturalWidthSum = (ushort)padding?.Start + (ushort)padding?.End + iconPadding.Start + iconPadding.End + (float)Icon?.SizeWidth + TextLabel.GetNaturalSize().Width;
+                    var naturalWidthDiff = SizeWidth - naturalWidthSum;
+
+                    if (naturalWidthDiff > 0)
+                    {
+                        TextLabel.SizeWidth = TextLabel.GetNaturalSize().Width;
+                    }
+                    else
+                    {
+                        TextLabel.SizeWidth = SizeWidth - (ushort)padding?.Start - (ushort)padding?.End - iconPadding.Start - iconPadding.End - textPadding.Start - textPadding.End - (float)Icon?.SizeWidth;
+                    }
+                }
+            }
+
+            // Calculate positions of Icon and TextLabel.
+            switch (IconRelativeOrientation)
+            {
+                // TODO: Other orientation cases are not implemented yet.
+                case IconOrientation.Left:
+                    if (LayoutDirection == ViewLayoutDirectionType.LTR)
+                    {
+                        if (Icon != null)
+                        {
+                            float iconX = 0;
+                            float iconY = (ushort)padding?.Top + iconPadding.Top;
+
+                            if (string.IsNullOrEmpty(TextLabel?.Text))
+                            {
+                                iconX = (SizeWidth - Icon.SizeWidth) / 2;
+                            }
+                            else
+                            {
+                                var widthSum = (ushort)padding?.Start + (ushort)padding?.End + iconPadding.Start + iconPadding.End + textPadding.Start + textPadding.End + Icon.SizeWidth + (float)TextLabel?.SizeWidth;
+                                var widthDiff = SizeWidth - widthSum;
+
+                                if (widthDiff > 0)
+                                {
+                                    iconX = (ushort)padding?.Start + iconPadding.Start + (widthDiff / 2);
+                                }
+                                else
+                                {
+                                    iconX = (ushort)padding?.Start + iconPadding.Start;
+                                }
+                            }
+
+                            Icon.Position = new Position(iconX, iconY);
+                        }
+
+                        if (TextLabel != null)
+                        {
+                            TextLabel.HorizontalAlignment = HorizontalAlignment.Begin;
+
+                            float textX = 0;
+                            float textY = 0;
+
+                            if (string.IsNullOrEmpty(Icon?.ResourceUrl))
+                            {
+                                textX = (SizeWidth - TextLabel.SizeWidth) / 2;
+                                textY = (ushort)padding?.Top + textPadding.Top;
+                            }
+                            else
+                            {
+                                textX = (float)Icon?.PositionX + (float)Icon?.SizeWidth;
+                                textY = (ushort)padding?.Top + textPadding.Top + (((float)Icon?.SizeHeight - TextLabel.SizeHeight) / 2);
+                            }
+
+                            TextLabel.Position = new Position(textX, textY);
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            padding?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            Layout = new AbsoluteLayout();
+
+            topLine = new View(tabButtonStyle?.TopLine);
+            Add(topLine);
+
+            bottomLine = new View(tabButtonStyle?.BottomLine);
+            Add(bottomLine);
+        }
     }
 }
diff --git a/src/Tizen.NUI.Components/Style/TabButtonStyle.cs b/src/Tizen.NUI.Components/Style/TabButtonStyle.cs
new file mode 100755 (executable)
index 0000000..ae33eef
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright(c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System.ComponentModel;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Components
+{
+    /// <summary>
+    /// TabButtonStyle is a class which saves TabButton's ux data.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class TabButtonStyle : ButtonStyle
+    {
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        static TabButtonStyle() { }
+
+        /// <summary>
+        /// Creates a new instance of a TabButtonStyle.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TabButtonStyle() : base()
+        {
+        }
+
+        /// <summary>
+        /// Creates a new instance of a TabButtonStyle with style.
+        /// </summary>
+        /// <param name="style">Create TabButtonStyle by style customized by user.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public TabButtonStyle(TabButtonStyle style) : base(style)
+        {
+        }
+
+        /// <summary>
+        /// Gets or Sets the Line Style at the top of TabButton.
+        /// </summary>
+        internal ViewStyle TopLine { get; set; } = new ViewStyle();
+
+        /// <summary>
+        /// Gets or Sets the Line Style at the bottom of TabButton.
+        /// </summary>
+        internal ViewStyle BottomLine { get; set; } = new ViewStyle();
+
+        /// <summary>
+        /// Style's clone function.
+        /// </summary>
+        /// <param name="bindableObject">The style that need to copy.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override void CopyFrom(BindableObject bindableObject)
+        {
+            base.CopyFrom(bindableObject);
+
+            if (bindableObject is TabButtonStyle tabButtonStyle)
+            {
+                TopLine.CopyFrom(tabButtonStyle.TopLine);
+                BottomLine.CopyFrom(tabButtonStyle.BottomLine);
+            }
+        }
+    }
+}
index d501a06..fe5683a 100755 (executable)
@@ -112,6 +112,22 @@ namespace Tizen.NUI.Components
                     .AddSelector("/ItemTextLabel/TextColor", (ViewStyle style, Selector<Color> value) => ((PickerStyle)style).ItemTextLabel.TextColor = value)
                     .AddSelector("/ItemTextLabel/PixelSize", (ViewStyle style, Selector<float?> value) => ((PickerStyle)style).ItemTextLabel.PixelSize = value)
                     .AddSelector("/Divider/Background", (ViewStyle style, Selector<Color> value) => ((PickerStyle)style).Divider.BackgroundColor = value),
+
+                // TabButton
+                (new ExternalThemeKeyList(typeof(TabButton), typeof(TabButtonStyle)))
+                    .Add<Size>("/Size", (ViewStyle style, Size value) => ((ViewStyle)style).Size = value)
+                    .Add<float?>("/CornerRadius", (ViewStyle style, float? value) => ((ViewStyle)style).CornerRadius = value)
+                    .AddSelector<Color>("/BackgroundColor", (ViewStyle style, Selector<Color> value) => ((ViewStyle)style).BackgroundColor = value, ControlState.Selected)
+                    .AddSelector<float?>("/Text/PixelSize", SetButtonTextPixelSize, ControlState.Selected)
+                    .Add<Size>("/Text/Size", (ViewStyle style, Size value) => ((ButtonStyle)style).Text.Size = value)
+                    .AddSelector<Color>("/Text/TextColor", SetButtonTextColor, ControlState.Selected)
+                    .Add<Size>("/Icon/Size", (ViewStyle style, Size value) => ((ButtonStyle)style).Icon.Size = value)
+                    .AddSelector<Color>("/Icon/Color", (ViewStyle style, Selector<Color> value) => ((ButtonStyle)style).Icon.Color = value, ControlState.Selected)
+                    .Add<Size>("/TopLine/Size", (ViewStyle style, Size value) => ((TabButtonStyle)style).TopLine.Size = value)
+                    .AddSelector<Color>("/TopLine/BackgroundColor", (ViewStyle style, Selector<Color> value) => ((TabButtonStyle)style).TopLine.BackgroundColor = value, ControlState.Selected)
+                    .Add<Size>("/BottomLine/Size", (ViewStyle style, Size value) => ((TabButtonStyle)style).BottomLine.Size = value)
+                    .Add<Position>("/BottomLine/Position", (ViewStyle style, Position value) => ((TabButtonStyle)style).BottomLine.Position = value)
+                    .AddSelector<Color>("/BottomLine/BackgroundColor", (ViewStyle style, Selector<Color> value) => ((TabButtonStyle)style).BottomLine.BackgroundColor = value, ControlState.Selected),
             };
 
             return actionSet;
index f1ce065..181be2d 100755 (executable)
@@ -435,6 +435,59 @@ namespace Tizen.NUI.Components
                 StartScrollOffset = new Size2D(0, 12),
             });
 
+            theme.AddStyleWithoutClone("Tizen.NUI.Components.TabButton", new TabButtonStyle()
+            {
+                Size = new Size(-1, 84),
+                CornerRadius = 0,
+                BackgroundColor = Color.White,
+                Text = new TextLabelStyle()
+                {
+                    PixelSize = 28,
+                    Size = new Size(-2, -2),
+                    TextColor = new Selector<Color>()
+                    {
+                        Normal = new Color("#000C2BFF"),
+                        Selected = new Color("#000C2BFF"),
+                        Pressed = new Color("#1473E6FF"),
+                        Disabled = new Color("#C3CAD2FF"),
+                    },
+                },
+                Icon = new ImageViewStyle()
+                {
+                    Size = new Size(48, 48),
+                    Color = new Selector<Color>()
+                    {
+                        Normal = new Color("#000C2BFF"),
+                        Selected = new Color("#000C2BFF"),
+                        Pressed = new Color("#1473E6FF"),
+                        Disabled = new Color("#C3CAD2FF"),
+                    },
+                },
+                TopLine = new ViewStyle()
+                {
+                    Size = new Size(-1, 1),
+                    BackgroundColor = new Selector<Color>()
+                    {
+                        Normal = new Color("#000C2BFF"),
+                        Selected = new Color("#000C2BFF"),
+                        Pressed = new Color("#1473E6FF"),
+                        Disabled = new Color("#C3CAD2FF"),
+                    },
+                },
+                BottomLine = new ViewStyle()
+                {
+                    Size = new Size(-1, 8),
+                    Position = new Position(0, 76), // 84 - 8
+                    BackgroundColor = new Selector<Color>()
+                    {
+                        Normal = Color.Transparent,
+                        Selected = new Color("#000C2BFF"),
+                        Pressed = new Color("#1473E6FF"),
+                        Disabled = Color.Transparent,
+                    },
+                },
+            });
+
             return theme;
         }
     }