[NUI] Introduce CollectionView and related classes. (#2525)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / Item / DefaultLinearItem.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.Binding;
20 using Tizen.NUI.Components.Extension;
21 using Tizen.NUI.Accessibility;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// DefaultLinearItem is one kind of common component, a DefaultLinearItem clearly describes what action will occur when the user selects it.
27     /// DefaultLinearItem may contain text or an icon.
28     /// </summary>
29     [EditorBrowsable(EditorBrowsableState.Never)]
30     public class DefaultLinearItem : RecyclerViewItem
31     {
32         private View itemIcon;
33         private TextLabel itemLabel;
34         private TextLabel itemSubLabel;
35         private View itemExtra;
36         private View itemSeperator;
37         private bool layoutChanged;
38         private Size prevSize;
39         private DefaultLinearItemStyle ItemStyle => ViewStyle as DefaultLinearItemStyle;
40
41         /// <summary>
42         /// Return a copied Style instance of DefaultLinearItem
43         /// </summary>
44         /// <remarks>
45         /// It returns copied Style instance and changing it does not effect to the DefaultLinearItem.
46         /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
47         /// </remarks>
48         [EditorBrowsable(EditorBrowsableState.Never)]
49         public new DefaultLinearItemStyle Style
50         {
51             get
52             {
53                 var result = new DefaultLinearItemStyle(ItemStyle);
54                 result.CopyPropertiesFromView(this);
55                 if (itemLabel) result.Label.CopyPropertiesFromView(itemLabel);
56                 if (itemSubLabel) result.SubLabel.CopyPropertiesFromView(itemSubLabel);
57                 if (itemIcon) result.Icon.CopyPropertiesFromView(itemIcon);
58                 if (itemExtra) result.Extra.CopyPropertiesFromView(itemExtra);
59                 if (itemSeperator) result.Seperator.CopyPropertiesFromView(itemSeperator);
60
61                 return result;
62             }
63         }
64
65         static DefaultLinearItem() {}
66
67         /// <summary>
68         /// Creates a new instance of DefaultLinearItem.
69         /// </summary>
70         [EditorBrowsable(EditorBrowsableState.Never)]
71         public DefaultLinearItem() : base()
72         {
73             Initialize();
74         }
75
76         /// <summary>
77         /// Creates a new instance of a DefaultLinearItem with style.
78         /// </summary>
79         /// <param name="style">Create DefaultLinearItem by style defined in UX.</param>
80         [EditorBrowsable(EditorBrowsableState.Never)]
81         public DefaultLinearItem(string style) : base(style)
82         {
83             Initialize();
84         }
85
86         /// <summary>
87         /// Creates a new instance of a DefaultLinearItem with style.
88         /// </summary>
89         /// <param name="itemStyle">Create DefaultLinearItem by style customized by user.</param>
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         public DefaultLinearItem(DefaultLinearItemStyle itemStyle) : base(itemStyle)
92         {
93             Initialize();
94         }
95
96         /// <summary>
97         /// Icon part of DefaultLinearItem.
98         /// </summary>
99         [EditorBrowsable(EditorBrowsableState.Never)]
100         public View Icon
101         {
102             get
103             {
104                 if (itemIcon == null)
105                 {
106                     itemIcon = CreateIcon(ItemStyle?.Icon);
107                     if (itemIcon != null)
108                     {
109                         layoutChanged = true;
110                         Add(itemIcon);
111                         itemIcon.Relayout += OnIconRelayout;
112                     }
113                 }
114                 return itemIcon;
115             }
116             set
117             {
118                 itemIcon = value;
119             }
120         }
121
122         /* open when imageView using Uri not string.
123         /// <summary>
124         /// Icon image's resource url. Only activatable for icon as ImageView.
125         /// </summary>
126         [EditorBrowsable(EditorBrowsableState.Never)]
127         public string IconUrl
128         {
129             get
130             {
131                 return (Icon as ImageView)?.ResourceUrl;
132             }
133             set
134             {
135                 if (itemIcon != null && !(itemIcon is ImageView))
136                 {
137                     // Tizen.Log.Error("IconUrl only can set Icon is ImageView");
138                     return;
139                 }
140                 (Icon as ImageView).ResourceUrl = value; 
141             }
142         }
143         */
144
145         /// <summary>
146         /// DefaultLinearItem's text part of DefaultLinearItem
147         /// </summary>
148         [EditorBrowsable(EditorBrowsableState.Never)]
149         public TextLabel Label
150         {
151             get
152             {
153                 if (itemLabel == null)
154                 {
155                     itemLabel = CreateLabel(ItemStyle?.Label);
156                     if (itemLabel != null)
157                     {
158                         layoutChanged = true;
159                         Add(itemLabel);
160                     }
161                 }
162                 return itemLabel;
163             }
164             internal set
165             {
166                 itemLabel = value;
167                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemLabel.Text);
168             }
169         }
170
171         /// <summary>
172         /// The text of DefaultLinearItem.
173         /// </summary>
174        [EditorBrowsable(EditorBrowsableState.Never)]
175         public string Text
176         {
177             get
178             {
179                 return Label.Text;
180             }
181             set
182             {
183                 Label.Text = value;
184             }
185         }
186
187         /// <summary>
188         /// DefaultLinearItem's secondary text part of DefaultLinearItem
189         /// </summary>
190         [EditorBrowsable(EditorBrowsableState.Never)]
191         public TextLabel SubLabel
192         {
193             get
194             {
195                 if (itemSubLabel == null)
196                 {
197                     itemSubLabel = CreateLabel(ItemStyle?.SubLabel);
198                     if (itemLabel != null)
199                     {
200                         layoutChanged = true;
201                         Add(itemSubLabel);
202                     }
203                 }
204                 return itemSubLabel;
205             }
206             internal set
207             {
208                 itemSubLabel = value;
209                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemSubLabel.Text);
210             }
211         }
212
213         /// <summary>
214         /// The text of DefaultLinearItem.
215         /// </summary>
216        [EditorBrowsable(EditorBrowsableState.Never)]
217         public string SubText
218         {
219             get
220             {
221                 return SubLabel.Text;
222             }
223             set
224             {
225                 SubLabel.Text = value;
226             }
227         }
228
229         /// <summary>
230         /// Extra icon part of DefaultLinearItem. it will place next of label.
231         /// </summary>
232         [EditorBrowsable(EditorBrowsableState.Never)]
233         public View Extra
234         {
235             get
236             {
237                 if (itemExtra == null)
238                 {
239                     itemExtra = CreateIcon(ItemStyle?.Extra);
240                     if (itemExtra != null)
241                     {
242                         layoutChanged = true;
243                         Add(itemExtra);
244                         itemExtra.Relayout += OnExtraRelayout;
245                     }
246                 }
247                 return itemExtra;
248             }
249             set
250             {
251                 if (itemExtra != null) Remove(itemExtra);
252                 itemExtra = value;
253                 Add(itemExtra);
254             }
255         }
256
257         /// <summary>
258         /// Seperator devider of DefaultLinearItem. it will place at the end of item.
259         /// </summary>
260         [EditorBrowsable(EditorBrowsableState.Never)]
261         public View Seperator
262         {
263             get
264             {
265                 if (itemSeperator == null)
266                 {
267                     itemSeperator = new View(ItemStyle?.Seperator)
268                     {
269                         //need to consider horizontal/vertical!
270                         WidthSpecification = LayoutParamPolicies.MatchParent,
271                         HeightSpecification = 2,
272                         ExcludeLayouting = true
273                     };
274                     layoutChanged = true;
275                     Add(itemSeperator);
276                 }
277                 return itemSeperator;
278             }
279         }
280
281         /// <summary>
282         /// Apply style to DefaultLinearItemStyle.
283         /// </summary>
284         /// <param name="viewStyle">The style to apply.</param>
285         [EditorBrowsable(EditorBrowsableState.Never)]
286         public override void ApplyStyle(ViewStyle viewStyle)
287         {
288
289             base.ApplyStyle(viewStyle);
290             if (viewStyle != null && viewStyle is DefaultLinearItemStyle defaultStyle)
291             {
292                 if (itemLabel != null)
293                     itemLabel.ApplyStyle(defaultStyle.Label);
294                 if (itemSubLabel != null)
295                     itemSubLabel.ApplyStyle(defaultStyle.SubLabel);
296                 if (itemIcon != null)
297                     itemIcon.ApplyStyle(defaultStyle.Icon);
298                 if (itemExtra != null)
299                     itemExtra.ApplyStyle(defaultStyle.Extra);
300                 if (itemSeperator != null)
301                     itemSeperator.ApplyStyle(defaultStyle.Seperator);
302             }
303         }
304
305         /// <inheritdoc />
306         [EditorBrowsable(EditorBrowsableState.Never)]
307         public override void OnRelayout(Vector2 size, RelayoutContainer container)
308         {
309             base.OnRelayout(size, container);
310
311             if (prevSize != Size)
312             {
313                 prevSize = Size;
314                 if (itemSeperator)
315                 {
316                     var margin = itemSeperator.Margin;
317                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
318                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
319                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom -itemSeperator.SizeHeight);
320                 }
321             }
322         }
323
324         /// <summary>
325         /// Creates Item's text part.
326         /// </summary>
327         /// <return>The created Item's text part.</return>
328         [EditorBrowsable(EditorBrowsableState.Never)]
329         protected virtual TextLabel CreateLabel(TextLabelStyle style)
330         {
331             return new TextLabel(style)
332             {
333                 HorizontalAlignment = HorizontalAlignment.Begin,
334                 VerticalAlignment = VerticalAlignment.Center
335             };
336         }
337
338         /// <summary>
339         /// Creates Item's icon part.
340         /// </summary>
341         /// <return>The created Item's icon part.</return>
342         [EditorBrowsable(EditorBrowsableState.Never)]
343         protected virtual ImageView CreateIcon(ViewStyle style)
344         {
345             return new ImageView(style);
346         }
347
348         /// <inheritdoc/>
349         [EditorBrowsable(EditorBrowsableState.Never)]
350         protected override void MeasureChild()
351         {
352             var pad = Padding;
353             if (itemLabel)
354             {
355                 var margin = itemLabel.Margin;
356                 itemLabel.SizeWidth = SizeWidth - pad.Start - pad.End - margin.Start - margin.End;
357             }
358
359             if (itemSubLabel)
360             {
361                 var margin = itemSubLabel.Margin;
362                 itemSubLabel.SizeWidth = SizeWidth - pad.Start - pad.End - margin.Start - margin.End;
363             }
364         }
365
366         /// <inheritdoc/>
367         [EditorBrowsable(EditorBrowsableState.Never)]
368         protected override void LayoutChild()
369         {
370             if (!layoutChanged) return;
371             if (itemLabel == null) return;
372
373             layoutChanged = false;
374
375             if (itemIcon != null)
376             {
377                 RelativeLayout.SetLeftTarget(itemIcon, this);
378                 RelativeLayout.SetLeftRelativeOffset(itemIcon, 0.0F);
379                 RelativeLayout.SetRightTarget(itemIcon, this);
380                 RelativeLayout.SetRightRelativeOffset(itemIcon, 0.0F);
381                 RelativeLayout.SetTopTarget(itemIcon, this);
382                 RelativeLayout.SetTopRelativeOffset(itemIcon, 0.0F);
383                 RelativeLayout.SetBottomTarget(itemIcon, this);
384                 RelativeLayout.SetBottomRelativeOffset(itemIcon, 1.0F);
385                 RelativeLayout.SetVerticalAlignment(itemIcon, RelativeLayout.Alignment.Center);
386                 RelativeLayout.SetHorizontalAlignment(itemIcon, RelativeLayout.Alignment.Start);
387             }
388
389             if (itemExtra != null)
390             {
391                 RelativeLayout.SetLeftTarget(itemExtra, this);
392                 RelativeLayout.SetLeftRelativeOffset(itemExtra, 1.0F);
393                 RelativeLayout.SetRightTarget(itemExtra, this);
394                 RelativeLayout.SetRightRelativeOffset(itemIcon, 1.0F);
395                 RelativeLayout.SetTopTarget(itemExtra, this);
396                 RelativeLayout.SetTopRelativeOffset(itemExtra, 0.0F);
397                 RelativeLayout.SetBottomTarget(itemExtra, this);
398                 RelativeLayout.SetBottomRelativeOffset(itemExtra, 1.0F);
399                 RelativeLayout.SetVerticalAlignment(itemExtra, RelativeLayout.Alignment.Center);
400                 RelativeLayout.SetHorizontalAlignment(itemExtra, RelativeLayout.Alignment.End);
401             }
402
403             if (itemSubLabel != null)
404             {
405                 if (itemIcon)
406                 {
407                     RelativeLayout.SetLeftTarget(itemSubLabel, itemIcon);
408                     RelativeLayout.SetLeftRelativeOffset(itemSubLabel, 1.0F);
409                 }
410                 else
411                 {
412                     RelativeLayout.SetLeftTarget(itemSubLabel, this);
413                     RelativeLayout.SetLeftRelativeOffset(itemSubLabel, 0.0F);
414                 }
415                 if (itemExtra)
416                 {
417                     RelativeLayout.SetRightTarget(itemSubLabel, itemExtra);
418                     RelativeLayout.SetRightRelativeOffset(itemSubLabel, 0.0F);
419                 }
420                 else
421                 {
422                     RelativeLayout.SetRightTarget(itemSubLabel, this);
423                     RelativeLayout.SetRightRelativeOffset(itemSubLabel, 1.0F);
424                 }
425
426                 RelativeLayout.SetTopTarget(itemSubLabel, this);
427                 RelativeLayout.SetTopRelativeOffset(itemSubLabel, 1.0F);
428                 RelativeLayout.SetBottomTarget(itemSubLabel, this);
429                 RelativeLayout.SetBottomRelativeOffset(itemSubLabel, 1.0F);
430                 RelativeLayout.SetVerticalAlignment(itemSubLabel, RelativeLayout.Alignment.End);
431
432                 RelativeLayout.SetHorizontalAlignment(itemSubLabel, RelativeLayout.Alignment.Center);
433                 RelativeLayout.SetFillHorizontal(itemSubLabel, true);
434             }
435
436             if (itemIcon)
437             {
438                 RelativeLayout.SetLeftTarget(itemLabel, itemIcon);
439                 RelativeLayout.SetLeftRelativeOffset(itemLabel, 1.0F);
440             }
441             else
442             {
443                 RelativeLayout.SetLeftTarget(itemLabel, this);
444                 RelativeLayout.SetLeftRelativeOffset(itemLabel, 0.0F);
445             }
446             if (itemExtra)
447             {
448                 RelativeLayout.SetRightTarget(itemLabel, itemExtra);
449                 RelativeLayout.SetRightRelativeOffset(itemLabel, 0.0F);
450             }
451             else
452             {
453                 RelativeLayout.SetRightTarget(itemLabel, this);
454                 RelativeLayout.SetRightRelativeOffset(itemLabel, 1.0F);
455             }
456
457             RelativeLayout.SetTopTarget(itemLabel, this);
458             RelativeLayout.SetTopRelativeOffset(itemLabel, 0.0F);
459
460             if (itemSubLabel)
461             {
462                 RelativeLayout.SetBottomTarget(itemLabel, itemSubLabel);
463                 RelativeLayout.SetBottomRelativeOffset(itemLabel, 0.0F);
464             }
465             else
466             {
467                 RelativeLayout.SetBottomTarget(itemLabel, this);
468                 RelativeLayout.SetBottomRelativeOffset(itemLabel, 1.0F);
469             }
470             RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.Center);
471             RelativeLayout.SetHorizontalAlignment(itemLabel, RelativeLayout.Alignment.Center);
472             RelativeLayout.SetFillHorizontal(itemLabel, true);
473
474             if (prevSize != Size)
475             {
476                 prevSize = Size;
477                 if (itemSeperator)
478                 {
479                     var margin = itemSeperator.Margin;
480                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
481                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
482                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom -itemSeperator.SizeHeight);
483                 }
484             }
485         }
486
487         /// <summary>
488         /// Dispose Item and all children on it.
489         /// </summary>
490         /// <param name="type">Dispose type.</param>
491         [EditorBrowsable(EditorBrowsableState.Never)]
492         protected override void Dispose(DisposeTypes type)
493         {
494             if (disposed)
495             {
496                 return;
497             }
498
499             if (type == DisposeTypes.Explicit)
500             {
501                 //Extension : Extension?.OnDispose(this);
502
503                 if (itemIcon != null)
504                 {
505                     Utility.Dispose(itemIcon);
506                 }
507                 if (itemExtra != null)
508                 {
509                     Utility.Dispose(itemExtra);
510                 }
511                 if (itemLabel != null)
512                 {
513                     Utility.Dispose(itemLabel);
514                 }
515                 if (itemSubLabel != null)
516                 {
517                     Utility.Dispose(itemSubLabel);
518                 }
519                 if (itemSeperator != null)
520                 {
521                     Utility.Dispose(itemSeperator);
522                 }
523             }
524
525             base.Dispose(type);
526         }
527
528         /// <summary>
529         /// Get DefaultLinearItem style.
530         /// </summary>
531         /// <returns>The default DefaultLinearItem style.</returns>
532         [EditorBrowsable(EditorBrowsableState.Never)]
533         protected override ViewStyle CreateViewStyle()
534         {
535             return new DefaultLinearItemStyle();
536         }
537
538         private void Initialize()
539         {
540             base.OnInitialize();
541             Layout = new RelativeLayout();
542             var seperator = Seperator;
543             layoutChanged = true;
544             LayoutDirectionChanged += OnLayoutDirectionChanged;
545         }
546
547         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
548         {
549             MeasureChild();
550             LayoutChild();
551         }
552
553         private void OnIconRelayout(object sender, EventArgs e)
554         {
555             MeasureChild();
556             LayoutChild();
557         }
558
559         private void OnExtraRelayout(object sender, EventArgs e)
560         {
561             MeasureChild();
562             LayoutChild();
563         }        
564     }
565 }