[NUI] Apply Padding and Margin on CollectionView and Layouter with styles (#2883)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / Item / DefaultTitleItem.cs
1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  */
16 using System;
17 using System.ComponentModel;
18 using Tizen.NUI.BaseComponents;
19 using Tizen.NUI.Accessibility;
20
21 namespace Tizen.NUI.Components
22 {
23     /// <summary>
24     /// DefaultTitleItem is one kind of common component, a DefaultTitleItem clearly describes what action will occur when the user selects it.
25     /// DefaultTitleItem may contain text or an icon.
26     /// </summary>
27     [EditorBrowsable(EditorBrowsableState.Never)]
28     public class DefaultTitleItem : RecyclerViewItem
29     {
30         private TextLabel itemLabel;
31         private View itemIcon;
32         private View itemSeperator;
33         private bool layoutChanged;
34         private Size prevSize;
35         private DefaultTitleItemStyle ItemStyle => ViewStyle as DefaultTitleItemStyle;
36
37         static DefaultTitleItem() { }
38
39         /// <summary>
40         /// Creates a new instance of DefaultTitleItem.
41         /// </summary>
42         [EditorBrowsable(EditorBrowsableState.Never)]
43         public DefaultTitleItem() : base()
44         {
45         }
46
47         /// <summary>
48         /// Creates a new instance of a DefaultTitleItem with style.
49         /// </summary>
50         /// <param name="style">Create DefaultTitleItem by style defined in UX.</param>
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public DefaultTitleItem(string style) : base(style)
53         {
54         }
55
56         /// <summary>
57         /// Creates a new instance of a DefaultTitleItem with style.
58         /// </summary>
59         /// <param name="itemStyle">Create DefaultTitleItem by style customized by user.</param>
60         [EditorBrowsable(EditorBrowsableState.Never)]
61         public DefaultTitleItem(DefaultTitleItemStyle itemStyle) : base(itemStyle)
62         {
63         }
64
65         /// <summary>
66         /// Icon part of DefaultTitleItem.
67         /// </summary>
68         [EditorBrowsable(EditorBrowsableState.Never)]
69         public View Icon
70         {
71             get
72             {
73                 if (itemIcon == null)
74                 {
75                     itemIcon = CreateIcon(ItemStyle?.Icon);
76                     if (itemIcon != null)
77                     {
78                         layoutChanged = true;
79                         Add(itemIcon);
80                         itemIcon.Relayout += OnIconRelayout;
81                     }
82                 }
83                 return itemIcon;
84             }
85             set
86             {
87                 itemIcon = value;
88             }
89         }
90
91         /* open when imageView using Uri not string.
92         /// <summary>
93         /// Icon image's resource url. Only activatable for icon as ImageView.
94         /// </summary>
95         [EditorBrowsable(EditorBrowsableState.Never)]
96         public string IconUrl
97         {
98             get
99             {
100                 return (Icon as ImageView)?.ResourceUrl;
101             }
102             set
103             {
104                 if (itemIcon != null && !(itemIcon is ImageView))
105                 {
106                     // Tizen.Log.Error("IconUrl only can set Icon is ImageView");
107                     return;
108                 }
109                 (Icon as ImageView).ResourceUrl = value; 
110             }
111         }
112         */
113
114         /// <summary>
115         /// DefaultTitleItem's text part of DefaultTitleItem
116         /// </summary>
117         [EditorBrowsable(EditorBrowsableState.Never)]
118         public TextLabel Label
119         {
120             get
121             {
122                 if (itemLabel == null)
123                 {
124                     itemLabel = CreateLabel(ItemStyle?.Label);
125                     if (itemLabel != null)
126                     {
127                         layoutChanged = true;
128                         Add(itemLabel);
129                     }
130                 }
131                 return itemLabel;
132             }
133             internal set
134             {
135                 itemLabel = value;
136                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemLabel.Text);
137             }
138         }
139
140         /// <summary>
141         /// The text of DefaultTitleItem.
142         /// </summary>
143         [EditorBrowsable(EditorBrowsableState.Never)]
144         public string Text
145         {
146             get
147             {
148                 return Label.Text;
149             }
150             set
151             {
152                 Label.Text = value;
153             }
154         }
155
156         /// <summary>
157         /// Seperator divider of DefaultTitleItem. it will place at the end of item.
158         /// </summary>
159         [EditorBrowsable(EditorBrowsableState.Never)]
160         public View Seperator
161         {
162             get
163             {
164                 if (itemSeperator == null)
165                 {
166                     itemSeperator = new View(ItemStyle?.Seperator)
167                     {
168                         //need to consider horizontal/vertical!
169                         WidthSpecification = LayoutParamPolicies.MatchParent,
170                         HeightSpecification = 2,
171                         ExcludeLayouting = true
172                     };
173                     layoutChanged = true;
174                     Add(itemSeperator);
175                 }
176                 return itemSeperator;
177             }
178         }
179
180         /// <summary>
181         /// Apply style to DefaultTitleItemStyle.
182         /// </summary>
183         /// <param name="viewStyle">The style to apply.</param>
184         [EditorBrowsable(EditorBrowsableState.Never)]
185         public override void ApplyStyle(ViewStyle viewStyle)
186         {
187
188             base.ApplyStyle(viewStyle);
189             if (viewStyle != null && viewStyle is DefaultTitleItemStyle defaultStyle)
190             {
191                 if (itemLabel != null)
192                     itemLabel.ApplyStyle(defaultStyle.Label);
193                 if (itemIcon != null)
194                     itemIcon.ApplyStyle(defaultStyle.Icon);
195                 if (itemSeperator != null)
196                 {
197                     itemSeperator.ApplyStyle(defaultStyle.Seperator);
198                     //FIXME : currently padding and margin are not applied by ApplyStyle automatically as missing binding features.
199                     itemSeperator.Margin = new Extents(defaultStyle.Seperator.Margin);
200                 }
201             }
202         }
203
204         /// <inheritdoc />
205         [EditorBrowsable(EditorBrowsableState.Never)]
206         public override void OnRelayout(Vector2 size, RelayoutContainer container)
207         {
208             base.OnRelayout(size, container);
209
210             if (prevSize != Size)
211             {
212                 prevSize = Size;
213                 if (itemSeperator)
214                 {
215                     var margin = itemSeperator.Margin;
216                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
217                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
218                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom - itemSeperator.SizeHeight);
219                 }
220             }
221         }
222
223         /// <summary>
224         /// Creates Item's text part.
225         /// </summary>
226         /// <return>The created Item's text part.</return>
227         [EditorBrowsable(EditorBrowsableState.Never)]
228         protected virtual TextLabel CreateLabel(TextLabelStyle style)
229         {
230             return new TextLabel(style)
231             {
232                 HorizontalAlignment = HorizontalAlignment.Begin,
233                 VerticalAlignment = VerticalAlignment.Center
234             };
235         }
236
237         /// <summary>
238         /// Creates Item's icon part.
239         /// </summary>
240         /// <return>The created Item's icon part.</return>
241         [EditorBrowsable(EditorBrowsableState.Never)]
242         protected virtual ImageView CreateIcon(ViewStyle style)
243         {
244             return new ImageView(style);
245         }
246
247         /// <inheritdoc/>
248         [EditorBrowsable(EditorBrowsableState.Never)]
249         protected override void MeasureChild()
250         {
251             // Do measure in here if necessary.
252         }
253
254         /// <inheritdoc/>
255         [EditorBrowsable(EditorBrowsableState.Never)]
256         protected override void LayoutChild()
257         {
258             if (!layoutChanged) return;
259             if (itemLabel == null) return;
260
261             layoutChanged = false;
262
263             if (itemIcon != null)
264             {
265                 RelativeLayout.SetLeftTarget(itemIcon, this);
266                 RelativeLayout.SetLeftRelativeOffset(itemIcon, 1.0F);
267                 RelativeLayout.SetRightTarget(itemIcon, this);
268                 RelativeLayout.SetRightRelativeOffset(itemIcon, 1.0F);
269                 RelativeLayout.SetTopTarget(itemIcon, this);
270                 RelativeLayout.SetTopRelativeOffset(itemIcon, 0.0F);
271                 RelativeLayout.SetBottomTarget(itemIcon, this);
272                 RelativeLayout.SetBottomRelativeOffset(itemIcon, 1.0F);
273                 RelativeLayout.SetVerticalAlignment(itemIcon, RelativeLayout.Alignment.Center);
274                 RelativeLayout.SetHorizontalAlignment(itemIcon, RelativeLayout.Alignment.End);
275             }
276
277             RelativeLayout.SetLeftTarget(itemLabel, this);
278             RelativeLayout.SetLeftRelativeOffset(itemLabel, 0.0F);
279             if (itemIcon)
280             {
281                 RelativeLayout.SetRightTarget(itemLabel, itemIcon);
282                 RelativeLayout.SetRightRelativeOffset(itemLabel, 0.0F);
283             }
284             else
285             {
286                 RelativeLayout.SetRightTarget(itemLabel, this);
287                 RelativeLayout.SetRightRelativeOffset(itemLabel, 1.0F);
288             }
289
290             RelativeLayout.SetTopTarget(itemLabel, this);
291             RelativeLayout.SetTopRelativeOffset(itemLabel, 0.0F);
292             RelativeLayout.SetBottomTarget(itemLabel, this);
293             RelativeLayout.SetBottomRelativeOffset(itemLabel, 1.0F);
294             RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.Center);
295             RelativeLayout.SetHorizontalAlignment(itemLabel, RelativeLayout.Alignment.Center);
296             RelativeLayout.SetFillHorizontal(itemLabel, true);
297
298             if (prevSize != Size)
299             {
300                 prevSize = Size;
301                 if (itemSeperator)
302                 {
303                     var margin = itemSeperator.Margin;
304                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
305                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
306                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom - itemSeperator.SizeHeight);
307                 }
308             }
309         }
310
311         /// <summary>
312         /// Dispose Item and all children on it.
313         /// </summary>
314         /// <param name="type">Dispose type.</param>
315         [EditorBrowsable(EditorBrowsableState.Never)]
316         protected override void Dispose(DisposeTypes type)
317         {
318             if (disposed)
319             {
320                 return;
321             }
322
323             if (type == DisposeTypes.Explicit)
324             {
325                 //Extension : Extension?.OnDispose(this);
326
327                 if (itemIcon != null)
328                 {
329                     Utility.Dispose(itemIcon);
330                 }
331                 if (itemLabel != null)
332                 {
333                     Utility.Dispose(itemLabel);
334                 }
335                 if (itemSeperator != null)
336                 {
337                     Utility.Dispose(itemSeperator);
338                 }
339             }
340
341             base.Dispose(type);
342         }
343
344         /// <summary>
345         /// Get DefaultTitleItem style.
346         /// </summary>
347         /// <returns>The default DefaultTitleItem style.</returns>
348         [EditorBrowsable(EditorBrowsableState.Never)]
349         protected override ViewStyle CreateViewStyle()
350         {
351             return new DefaultTitleItemStyle();
352         }
353
354         /// <summary>
355         /// Initializes AT-SPI object.
356         /// </summary>
357         [EditorBrowsable(EditorBrowsableState.Never)]
358         public override void OnInitialize()
359         {
360             base.OnInitialize();
361             Layout = new RelativeLayout();
362             var seperator = Seperator;
363             layoutChanged = true;
364             LayoutDirectionChanged += OnLayoutDirectionChanged;
365         }
366
367         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
368         {
369             MeasureChild();
370             LayoutChild();
371         }
372
373         private void OnIconRelayout(object sender, EventArgs e)
374         {
375             MeasureChild();
376             LayoutChild();
377         }
378
379         private void OnExtraRelayout(object sender, EventArgs e)
380         {
381             MeasureChild();
382             LayoutChild();
383         }
384     }
385 }