Release 10.0.0.16997
[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                     itemLabel.AppendAccessibilityRelation(this, AccessibilityRelationType.ControlledBy);
154                     this.AppendAccessibilityRelation(itemLabel, AccessibilityRelationType.LabelledBy);
155                 }
156                 return itemLabel;
157             }
158             internal set
159             {
160                 itemLabel = value;
161                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemLabel.Text);
162             }
163         }
164
165         /// <summary>
166         /// The text of DefaultLinearItem.
167         /// </summary>
168         [EditorBrowsable(EditorBrowsableState.Never)]
169         public string Text
170         {
171             get
172             {
173                 return GetValue(TextProperty) as string;
174             }
175             set
176             {
177                 SetValue(TextProperty, value);
178                 NotifyPropertyChanged();
179             }
180         }
181         private string InternalText
182         {
183             get
184             {
185                 return Label.Text;
186             }
187             set
188             {
189                 Label.Text = value;
190             }
191         }
192
193         /// <summary>
194         /// DefaultLinearItem's secondary text part of DefaultLinearItem
195         /// </summary>
196         [EditorBrowsable(EditorBrowsableState.Never)]
197         public TextLabel SubLabel
198         {
199             get
200             {
201                 if (itemSubLabel == null)
202                 {
203                     itemSubLabel = CreateLabel(ItemStyle?.SubLabel);
204                     if (itemLabel != null)
205                     {
206                         layoutChanged = true;
207                         Add(itemSubLabel);
208                     }
209                 }
210                 return itemSubLabel;
211             }
212             internal set
213             {
214                 itemSubLabel = value;
215                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemSubLabel.Text);
216             }
217         }
218
219         /// <summary>
220         /// The text of DefaultLinearItem.
221         /// </summary>
222         [EditorBrowsable(EditorBrowsableState.Never)]
223         public string SubText
224         {
225             get
226             {
227                 return GetValue(SubTextProperty) as string;
228             }
229             set
230             {
231                 SetValue(SubTextProperty, value);
232                 NotifyPropertyChanged();
233             }
234         }
235         private string InternalSubText
236         {
237             get
238             {
239                 return SubLabel.Text;
240             }
241             set
242             {
243                 SubLabel.Text = value;
244             }
245         }
246
247         /// <summary>
248         /// Extra icon part of DefaultLinearItem. it will place next of label.
249         /// </summary>
250         [EditorBrowsable(EditorBrowsableState.Never)]
251         public View Extra
252         {
253             get
254             {
255                 return GetValue(ExtraProperty) as View;
256             }
257             set
258             {
259                 SetValue(ExtraProperty, value);
260                 NotifyPropertyChanged();
261             }
262         }
263         private View InternalExtra
264         {
265             get
266             {
267                 if (itemExtra == null)
268                 {
269                     itemExtra = CreateIcon(ItemStyle?.Extra);
270                     if (itemExtra != null)
271                     {
272                         layoutChanged = true;
273                         Add(itemExtra);
274                         itemExtra.Relayout += OnExtraRelayout;
275                     }
276                 }
277                 return itemExtra;
278             }
279             set
280             {
281                 if (itemExtra != null) Remove(itemExtra);
282                 itemExtra = value;
283                 if (itemExtra != null)
284                 {
285                     //FIXME: User applied extra's style can be overwritten!
286                     if (ItemStyle != null) itemExtra.ApplyStyle(ItemStyle.Extra);
287                     Add(itemExtra);
288                 }
289                 layoutChanged = true;
290             }
291         }
292
293         /// <summary>
294         /// Seperator divider of DefaultLinearItem. it will place at the end of item.
295         /// </summary>
296         [EditorBrowsable(EditorBrowsableState.Never)]
297         public View Seperator
298         {
299             get
300             {
301                 if (itemSeperator == null)
302                 {
303                     itemSeperator = new View(ItemStyle?.Seperator)
304                     {
305                         //need to consider horizontal/vertical!
306                         WidthSpecification = LayoutParamPolicies.MatchParent,
307                         HeightSpecification = 2,
308                         ExcludeLayouting = true
309                     };
310                     layoutChanged = true;
311                     Add(itemSeperator);
312                 }
313                 return itemSeperator;
314             }
315         }
316
317         /// <summary>
318         /// Apply style to DefaultLinearItemStyle.
319         /// </summary>
320         /// <param name="viewStyle">The style to apply.</param>
321         [EditorBrowsable(EditorBrowsableState.Never)]
322         public override void ApplyStyle(ViewStyle viewStyle)
323         {
324             base.ApplyStyle(viewStyle);
325             if (viewStyle != null && viewStyle is DefaultLinearItemStyle defaultStyle)
326             {
327                 if (itemLabel != null)
328                     itemLabel.ApplyStyle(defaultStyle.Label);
329                 if (itemSubLabel != null)
330                     itemSubLabel.ApplyStyle(defaultStyle.SubLabel);
331                 if (itemIcon != null)
332                     itemIcon.ApplyStyle(defaultStyle.Icon);
333                 if (itemExtra != null)
334                     itemExtra.ApplyStyle(defaultStyle.Extra);
335                 if (itemSeperator != null)
336                 {
337                     itemSeperator.ApplyStyle(defaultStyle.Seperator);
338                     //FIXME : currently padding and margin are not applied by ApplyStyle automatically as missing binding features.
339                     itemSeperator.Margin = new Extents(defaultStyle.Seperator.Margin);
340                 }
341             }
342         }
343
344         /// <inheritdoc />
345         [EditorBrowsable(EditorBrowsableState.Never)]
346         public override void OnRelayout(Vector2 size, RelayoutContainer container)
347         {
348             base.OnRelayout(size, container);
349
350             if (prevSize != Size)
351             {
352                 prevSize = Size;
353                 if (itemSeperator)
354                 {
355                     var margin = itemSeperator.Margin;
356                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
357                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
358                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom - itemSeperator.SizeHeight);
359                 }
360             }
361         }
362
363         /// <summary>
364         /// Creates Item's text part.
365         /// </summary>
366         /// <return>The created Item's text part.</return>
367         [EditorBrowsable(EditorBrowsableState.Never)]
368         protected virtual TextLabel CreateLabel(TextLabelStyle style)
369         {
370             return new TextLabel(style)
371             {
372                 HorizontalAlignment = HorizontalAlignment.Begin,
373                 VerticalAlignment = VerticalAlignment.Center
374             };
375         }
376
377         /// <summary>
378         /// Creates Item's icon part.
379         /// </summary>
380         /// <return>The created Item's icon part.</return>
381         [EditorBrowsable(EditorBrowsableState.Never)]
382         protected virtual ImageView CreateIcon(ViewStyle style)
383         {
384             return new ImageView(style);
385         }
386
387         /// <inheritdoc/>
388         [EditorBrowsable(EditorBrowsableState.Never)]
389         protected override void MeasureChild()
390         {
391             //Do Measure in here if necessary.
392         }
393
394         /// <inheritdoc/>
395         [EditorBrowsable(EditorBrowsableState.Never)]
396         protected override void LayoutChild()
397         {
398             if (!layoutChanged) return;
399             if (itemLabel == null) return;
400
401             layoutChanged = false;
402
403             if (itemIcon != null)
404             {
405                 RelativeLayout.SetLeftTarget(itemIcon, this);
406                 RelativeLayout.SetLeftRelativeOffset(itemIcon, 0.0F);
407                 RelativeLayout.SetRightTarget(itemIcon, this);
408                 RelativeLayout.SetRightRelativeOffset(itemIcon, 0.0F);
409                 RelativeLayout.SetTopTarget(itemIcon, this);
410                 RelativeLayout.SetTopRelativeOffset(itemIcon, 0.0F);
411                 RelativeLayout.SetBottomTarget(itemIcon, this);
412                 RelativeLayout.SetBottomRelativeOffset(itemIcon, 1.0F);
413                 RelativeLayout.SetVerticalAlignment(itemIcon, RelativeLayout.Alignment.Center);
414                 RelativeLayout.SetHorizontalAlignment(itemIcon, RelativeLayout.Alignment.Start);
415             }
416
417             if (itemExtra != null)
418             {
419                 RelativeLayout.SetLeftTarget(itemExtra, this);
420                 RelativeLayout.SetLeftRelativeOffset(itemExtra, 1.0F);
421                 RelativeLayout.SetRightTarget(itemExtra, this);
422                 RelativeLayout.SetRightRelativeOffset(itemExtra, 1.0F);
423                 RelativeLayout.SetTopTarget(itemExtra, this);
424                 RelativeLayout.SetTopRelativeOffset(itemExtra, 0.0F);
425                 RelativeLayout.SetBottomTarget(itemExtra, this);
426                 RelativeLayout.SetBottomRelativeOffset(itemExtra, 1.0F);
427                 RelativeLayout.SetVerticalAlignment(itemExtra, RelativeLayout.Alignment.Center);
428                 RelativeLayout.SetHorizontalAlignment(itemExtra, RelativeLayout.Alignment.End);
429             }
430
431             if (itemSubLabel != null)
432             {
433                 RelativeLayout.SetLeftTarget(itemSubLabel,  ((itemIcon != null)? itemIcon : this));
434                 RelativeLayout.SetLeftRelativeOffset(itemSubLabel, ( (itemIcon != null)? 1.0F : 0.0F));
435                 RelativeLayout.SetRightTarget(itemSubLabel, ((itemExtra != null)? itemExtra : this));
436                 RelativeLayout.SetRightRelativeOffset(itemSubLabel, ((itemExtra != null)? 0.0F : 1.0F));
437                 RelativeLayout.SetTopTarget(itemSubLabel, this);
438                 RelativeLayout.SetTopRelativeOffset(itemSubLabel, 1.0F);
439                 RelativeLayout.SetBottomTarget(itemSubLabel, this);
440                 RelativeLayout.SetBottomRelativeOffset(itemSubLabel, 1.0F);
441                 RelativeLayout.SetVerticalAlignment(itemSubLabel, RelativeLayout.Alignment.End);
442                 RelativeLayout.SetHorizontalAlignment(itemSubLabel, RelativeLayout.Alignment.Center);
443                 RelativeLayout.SetFillHorizontal(itemSubLabel, true);
444             }
445
446             RelativeLayout.SetLeftTarget(itemLabel, ((itemIcon != null)? itemIcon : this));
447             RelativeLayout.SetLeftRelativeOffset(itemLabel, ((itemIcon != null)? 1.0F : 0.0F));
448             RelativeLayout.SetRightTarget(itemLabel, ((itemExtra != null)? itemExtra : this));
449             RelativeLayout.SetRightRelativeOffset(itemLabel, ((itemExtra != null)? 0.0F : 1.0F));
450             RelativeLayout.SetTopTarget(itemLabel, this);
451             RelativeLayout.SetTopRelativeOffset(itemLabel, 0.0F);
452             RelativeLayout.SetBottomTarget(itemLabel, ((itemSubLabel != null)? (View)itemSubLabel : this));
453             RelativeLayout.SetBottomRelativeOffset(itemLabel, ((itemSubLabel != null)? 0.0F : 1.0F));
454             RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.Center);
455             RelativeLayout.SetHorizontalAlignment(itemLabel, RelativeLayout.Alignment.Center);
456             RelativeLayout.SetFillHorizontal(itemLabel, true);
457
458             if (prevSize != Size)
459             {
460                 prevSize = Size;
461                 if (itemSeperator)
462                 {
463                     var margin = itemSeperator.Margin;
464                     itemSeperator.SizeWidth = SizeWidth - margin.Start - margin.End;
465                     itemSeperator.SizeHeight = itemSeperator.HeightSpecification;
466                     itemSeperator.Position = new Position(margin.Start, SizeHeight - margin.Bottom - itemSeperator.SizeHeight);
467                 }
468             }
469         }
470
471         /// <summary>
472         /// Dispose Item and all children on it.
473         /// </summary>
474         /// <param name="type">Dispose type.</param>
475         [EditorBrowsable(EditorBrowsableState.Never)]
476         protected override void Dispose(DisposeTypes type)
477         {
478             if (disposed)
479             {
480                 return;
481             }
482
483             if (type == DisposeTypes.Explicit)
484             {
485                 //Extension : Extension?.OnDispose(this);
486
487                 // Arugable to disposing user-created members.
488                 /*
489                 if (itemIcon != null)
490                 {
491                     Utility.Dispose(itemIcon);
492                 }
493                 if (itemExtra != null)
494                 {
495                     Utility.Dispose(itemExtra);
496                 }
497                 */
498                 if (itemLabel != null)
499                 {
500                     Utility.Dispose(itemLabel);
501                     itemLabel = null;
502                 }
503                 if (itemSubLabel != null)
504                 {
505                     Utility.Dispose(itemSubLabel);
506                     itemSubLabel = null;
507                 }
508                 if (itemSeperator != null)
509                 {
510                     Utility.Dispose(itemSeperator);
511                     itemSeperator = null;
512                 }
513             }
514
515             base.Dispose(type);
516         }
517
518         /// <summary>
519         /// Get DefaultLinearItem style.
520         /// </summary>
521         /// <returns>The default DefaultLinearItem style.</returns>
522         [EditorBrowsable(EditorBrowsableState.Never)]
523         protected override ViewStyle CreateViewStyle()
524         {
525             return new DefaultLinearItemStyle();
526         }
527
528         /// <summary>
529         /// Initializes AT-SPI object.
530         /// </summary>
531         [EditorBrowsable(EditorBrowsableState.Never)]
532         public override void OnInitialize()
533         {
534             base.OnInitialize();
535             Layout = new RelativeLayout();
536             var seperator = Seperator;
537             layoutChanged = true;
538             LayoutDirectionChanged += OnLayoutDirectionChanged;
539         }
540
541         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
542         {
543             MeasureChild();
544             LayoutChild();
545         }
546
547         private void OnIconRelayout(object sender, EventArgs e)
548         {
549             MeasureChild();
550             LayoutChild();
551         }
552
553         private void OnExtraRelayout(object sender, EventArgs e)
554         {
555             MeasureChild();
556             LayoutChild();
557         }
558     }
559 }