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