[NUI] fix bug in item's content set (#3191)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / Item / DefaultGridItem.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     /// DefaultGridItem is one kind of common component, a DefaultGridItem clearly describes what action will occur when the user selects it.
25     /// DefaultGridItem may contain text or an icon.
26     /// </summary>
27     [EditorBrowsable(EditorBrowsableState.Never)]
28     public class DefaultGridItem : RecyclerViewItem
29     {
30         private TextLabel itemLabel;
31         private ImageView itemImage;
32         private View itemBadge;
33         private LabelOrientation labelOrientation;
34         private bool layoutChanged;
35
36         private DefaultGridItemStyle ItemStyle => ViewStyle as DefaultGridItemStyle;
37
38         static DefaultGridItem() { }
39
40         /// <summary>
41         /// Creates a new instance of DefaultGridItem.
42         /// </summary>
43         [EditorBrowsable(EditorBrowsableState.Never)]
44         public DefaultGridItem() : base()
45         {
46         }
47
48         /// <summary>
49         /// Creates a new instance of DefaultGridItem with style
50         /// </summary>
51         /// <param name="style=">Create DefaultGridItem by special style defined in UX.</param>
52         [EditorBrowsable(EditorBrowsableState.Never)]
53         public DefaultGridItem(string style) : base(style)
54         {
55         }
56
57         /// <summary>
58         /// Creates a new instance of DefaultGridItem with style
59         /// </summary>
60         /// <param name="itemStyle=">Create DefaultGridItem by style customized by user.</param>
61         [EditorBrowsable(EditorBrowsableState.Never)]
62         public DefaultGridItem(DefaultGridItemStyle itemStyle) : base(itemStyle)
63         {
64         }
65
66         /// <summary>
67         /// Label orientation.
68         /// </summary>
69         [EditorBrowsable(EditorBrowsableState.Never)]
70         public enum LabelOrientation
71         {
72             /// <summary>
73             /// Outside of image bottom edge.
74             /// </summary>
75             [EditorBrowsable(EditorBrowsableState.Never)]
76             OutsideBottom,
77             /// <summary>
78             /// Outside of image top edge.
79             /// </summary>
80             [EditorBrowsable(EditorBrowsableState.Never)]
81             OutsideTop,
82             /// <summary>
83             /// inside of image bottom edge.
84             /// </summary>
85             [EditorBrowsable(EditorBrowsableState.Never)]
86             InsideBottom,
87             /// <summary>
88             /// inside of image top edge.
89             /// </summary>
90             [EditorBrowsable(EditorBrowsableState.Never)]
91             InsideTop,
92         }
93
94         /// <summary>
95         /// DefaultGridItem's icon part.
96         /// </summary>
97         [EditorBrowsable(EditorBrowsableState.Never)]
98         public ImageView Image
99         {
100             get
101             {
102                 if (itemImage == null)
103                 {
104                     itemImage = CreateImage(ItemStyle.Image);
105                     if (itemImage != null)
106                     {
107                         Add(itemImage);
108                         itemImage.Relayout += OnImageRelayout;
109                         layoutChanged = true;
110                     }
111                 }
112                 return itemImage;
113             }
114             internal set
115             {
116                 if (itemImage != null) Remove(itemImage);
117                 itemImage = value;
118                 if (itemImage != null)
119                 {
120                     //FIXME: User applied image's style can be overwritten!
121                     if (ItemStyle != null) itemImage.ApplyStyle(ItemStyle.Image);
122                     Add(itemImage);
123                     itemImage.Relayout += OnImageRelayout;
124                 }
125                 layoutChanged = true;
126             }
127         }
128
129
130         /// <summary>
131         /// DefaultGridItem's badge object. will be placed in right-top edge.
132         /// </summary>
133         [EditorBrowsable(EditorBrowsableState.Never)]
134         public View Badge
135         {
136             get
137             {
138                 return itemBadge;
139
140             }
141             set
142             {
143                 if (itemBadge != null) Remove(itemBadge);
144                 itemBadge = value;
145                 if (itemBadge != null)
146                 {
147                     //FIXME: User applied badge's style can be overwritten!
148                     if (ItemStyle != null) itemBadge.ApplyStyle(ItemStyle.Badge);
149                     Add(itemBadge);
150                 }
151                 layoutChanged = true;
152             }
153         }
154
155         /* open when ImageView using Uri not string
156                 /// <summary>
157                 /// Image image's resource url in DefaultGridItem.
158                 /// </summary>
159                 [EditorBrowsable(EditorBrowsableState.Never)]
160                 public string ImageUrl
161                 {
162                     get
163                     {
164                         return Image.ResourceUrl;
165                     }
166                     set
167                     {
168                         Image.ResourceUrl = value;
169                     }
170                 }
171         */
172
173         /// <summary>
174         /// DefaultGridItem's text part.
175         /// </summary>
176         [EditorBrowsable(EditorBrowsableState.Never)]
177         public TextLabel Label
178         {
179             get
180             {
181                 if (itemLabel == null)
182                 {
183                     itemLabel = CreateLabel(ItemStyle.Label);
184                     if (itemLabel != null)
185                     {
186                         Add(itemLabel);
187                         layoutChanged = true;
188                     }
189                 }
190                 return itemLabel;
191             }
192             internal set
193             {
194                 itemLabel = value;
195                 layoutChanged = true;
196                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, itemLabel.Text);
197             }
198         }
199
200         /// <summary>
201         /// The text of DefaultGridItem.
202         /// </summary>
203         [EditorBrowsable(EditorBrowsableState.Never)]
204         public string Text
205         {
206             get
207             {
208                 return Label.Text;
209             }
210             set
211             {
212                 Label.Text = value;
213             }
214         }
215
216         /// <summary>
217         /// Label relative orientation with image in DefaultGridItem.
218         /// </summary>
219         [EditorBrowsable(EditorBrowsableState.Never)]
220         public LabelOrientation LabelOrientationType
221         {
222             get
223             {
224                 return labelOrientation;
225             }
226             set
227             {
228                 labelOrientation = value;
229                 layoutChanged = true;
230             }
231         }
232
233         /// <summary>
234         /// Apply style to DefaultLinearItemStyle.
235         /// </summary>
236         /// <param name="viewStyle">The style to apply.</param>
237         [EditorBrowsable(EditorBrowsableState.Never)]
238         public override void ApplyStyle(ViewStyle viewStyle)
239         {
240
241             base.ApplyStyle(viewStyle);
242             if (viewStyle != null && viewStyle is DefaultGridItemStyle defaultStyle)
243             {
244                 if (itemLabel != null)
245                     itemLabel.ApplyStyle(defaultStyle.Label);
246                 if (itemImage != null)
247                     itemImage.ApplyStyle(defaultStyle.Image);
248                 if (itemBadge != null)
249                     itemBadge.ApplyStyle(defaultStyle.Badge);
250             }
251         }
252
253         /// <summary>
254         /// Creates Item's text part.
255         /// </summary>
256         /// <return>The created Item's text part.</return>
257         [EditorBrowsable(EditorBrowsableState.Never)]
258         protected virtual TextLabel CreateLabel(TextLabelStyle textStyle)
259         {
260             return new TextLabel(textStyle)
261             {
262                 HorizontalAlignment = HorizontalAlignment.Center,
263                 VerticalAlignment = VerticalAlignment.Center
264             };
265         }
266
267         /// <summary>
268         /// Creates Item's icon part.
269         /// </summary>
270         /// <return>The created Item's icon part.</return>
271         [EditorBrowsable(EditorBrowsableState.Never)]
272         protected virtual ImageView CreateImage(ImageViewStyle imageStyle)
273         {
274             return new ImageView(imageStyle);
275         }
276
277         /// <inheritdoc/>
278         [EditorBrowsable(EditorBrowsableState.Never)]
279         protected override void MeasureChild()
280         {
281             //nothing to do.
282             if (itemLabel)
283             {
284                 var pad = Padding;
285                 var margin = itemLabel.Margin;
286                 itemLabel.SizeWidth = SizeWidth - pad.Start - pad.End - margin.Start - margin.End;
287             }
288         }
289
290         /// <inheritdoc/>
291         [EditorBrowsable(EditorBrowsableState.Never)]
292         protected override void LayoutChild()
293         {
294             if (!layoutChanged) return;
295             if (itemImage == null) return;
296
297             layoutChanged = false;
298
299             RelativeLayout.SetLeftTarget(itemImage, this);
300             RelativeLayout.SetLeftRelativeOffset(itemImage, 0.0F);
301             RelativeLayout.SetRightTarget(itemImage, this);
302             RelativeLayout.SetRightRelativeOffset(itemImage, 1.0F);
303             RelativeLayout.SetHorizontalAlignment(itemImage, RelativeLayout.Alignment.Center);
304
305             if (itemLabel != null)
306             {
307                 itemLabel.RaiseAbove(itemImage);
308                 RelativeLayout.SetLeftTarget(itemLabel, itemImage);
309                 RelativeLayout.SetLeftRelativeOffset(itemLabel, 0.0F);
310                 RelativeLayout.SetRightTarget(itemLabel, itemImage);
311                 RelativeLayout.SetRightRelativeOffset(itemLabel, 1.0F);
312                 RelativeLayout.SetHorizontalAlignment(itemLabel, RelativeLayout.Alignment.Center);
313                 RelativeLayout.SetFillHorizontal(itemLabel, true);
314             }
315             else
316             {
317                 RelativeLayout.SetTopTarget(itemImage, this);
318                 RelativeLayout.SetTopRelativeOffset(itemImage, 0.0F);
319                 RelativeLayout.SetBottomTarget(itemImage, this);
320                 RelativeLayout.SetBottomRelativeOffset(itemImage, 1.0F);
321                 RelativeLayout.SetVerticalAlignment(itemImage, RelativeLayout.Alignment.Center);
322             }
323
324             if (itemBadge)
325             {
326                 RelativeLayout.SetLeftTarget(itemBadge, itemImage);
327                 RelativeLayout.SetLeftRelativeOffset(itemBadge, 1.0F);
328                 RelativeLayout.SetRightTarget(itemBadge, itemImage);
329                 RelativeLayout.SetRightRelativeOffset(itemBadge, 1.0F);
330                 RelativeLayout.SetHorizontalAlignment(itemBadge, RelativeLayout.Alignment.End);
331             }
332
333             switch (labelOrientation)
334             {
335                 case LabelOrientation.OutsideBottom:
336                     if (itemLabel != null)
337                     {
338                         RelativeLayout.SetTopTarget(itemLabel, this);
339                         RelativeLayout.SetTopRelativeOffset(itemLabel, 1.0F);
340                         RelativeLayout.SetBottomTarget(itemLabel, this);
341                         RelativeLayout.SetBottomRelativeOffset(itemLabel, 1.0F);
342                         RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.End);
343
344                         RelativeLayout.SetTopTarget(itemImage, this);
345                         RelativeLayout.SetTopRelativeOffset(itemImage, 0.0F);
346                         RelativeLayout.SetBottomTarget(itemImage, itemLabel);
347                         RelativeLayout.SetBottomRelativeOffset(itemImage, 0.0F);
348                         RelativeLayout.SetVerticalAlignment(itemImage, RelativeLayout.Alignment.Center);
349                     }
350
351                     if (itemBadge)
352                     {
353                         RelativeLayout.SetTopTarget(itemBadge, itemImage);
354                         RelativeLayout.SetTopRelativeOffset(itemBadge, 0.0F);
355                         RelativeLayout.SetBottomTarget(itemBadge, itemImage);
356                         RelativeLayout.SetBottomRelativeOffset(itemBadge, 0.0F);
357                         RelativeLayout.SetVerticalAlignment(itemBadge, RelativeLayout.Alignment.Start);
358                     }
359                     break;
360
361                 case LabelOrientation.OutsideTop:
362                     if (itemLabel != null)
363                     {
364                         RelativeLayout.SetTopTarget(itemLabel, this);
365                         RelativeLayout.SetTopRelativeOffset(itemLabel, 0.0F);
366                         RelativeLayout.SetBottomTarget(itemLabel, this);
367                         RelativeLayout.SetBottomRelativeOffset(itemLabel, 0.0F);
368                         RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.Start);
369
370                         RelativeLayout.SetTopTarget(itemImage, itemLabel);
371                         RelativeLayout.SetTopRelativeOffset(itemImage, 1.0F);
372                         RelativeLayout.SetBottomTarget(itemImage, this);
373                         RelativeLayout.SetBottomRelativeOffset(itemImage, 1.0F);
374                         RelativeLayout.SetVerticalAlignment(itemImage, RelativeLayout.Alignment.Center);
375                     }
376
377                     if (itemBadge)
378                     {
379                         RelativeLayout.SetTopTarget(itemBadge, itemImage);
380                         RelativeLayout.SetTopRelativeOffset(itemBadge, 1.0F);
381                         RelativeLayout.SetBottomTarget(itemBadge, itemImage);
382                         RelativeLayout.SetBottomRelativeOffset(itemBadge, 1.0F);
383                         RelativeLayout.SetVerticalAlignment(itemBadge, RelativeLayout.Alignment.End);
384                     }
385                     break;
386
387                 case LabelOrientation.InsideBottom:
388                     if (itemLabel != null)
389                     {
390                         RelativeLayout.SetTopTarget(itemLabel, this);
391                         RelativeLayout.SetTopRelativeOffset(itemLabel, 1.0F);
392                         RelativeLayout.SetBottomTarget(itemLabel, this);
393                         RelativeLayout.SetBottomRelativeOffset(itemLabel, 1.0F);
394                         RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.End);
395
396                         RelativeLayout.SetTopTarget(itemImage, this);
397                         RelativeLayout.SetTopRelativeOffset(itemImage, 0.0F);
398                         RelativeLayout.SetBottomTarget(itemImage, this);
399                         RelativeLayout.SetBottomRelativeOffset(itemImage, 1.0F);
400                         RelativeLayout.SetVerticalAlignment(itemImage, RelativeLayout.Alignment.Center);
401                     }
402
403                     if (itemBadge)
404                     {
405                         RelativeLayout.SetTopTarget(itemBadge, itemImage);
406                         RelativeLayout.SetTopRelativeOffset(itemBadge, 0.0F);
407                         RelativeLayout.SetBottomTarget(itemBadge, itemImage);
408                         RelativeLayout.SetBottomRelativeOffset(itemBadge, 0.0F);
409                         RelativeLayout.SetVerticalAlignment(itemBadge, RelativeLayout.Alignment.Start);
410                     }
411                     break;
412
413                 case LabelOrientation.InsideTop:
414                     if (itemLabel != null)
415                     {
416                         RelativeLayout.SetTopTarget(itemLabel, this);
417                         RelativeLayout.SetTopRelativeOffset(itemLabel, 0.0F);
418                         RelativeLayout.SetBottomTarget(itemLabel, this);
419                         RelativeLayout.SetBottomRelativeOffset(itemLabel, 0.0F);
420                         RelativeLayout.SetVerticalAlignment(itemLabel, RelativeLayout.Alignment.Start);
421
422                         RelativeLayout.SetTopTarget(itemImage, this);
423                         RelativeLayout.SetTopRelativeOffset(itemImage, 0.0F);
424                         RelativeLayout.SetBottomTarget(itemImage, this);
425                         RelativeLayout.SetBottomRelativeOffset(itemImage, 1.0F);
426                         RelativeLayout.SetVerticalAlignment(itemImage, RelativeLayout.Alignment.Center);
427                     }
428
429                     if (itemBadge)
430                     {
431                         RelativeLayout.SetTopTarget(itemBadge, itemImage);
432                         RelativeLayout.SetTopRelativeOffset(itemBadge, 1.0F);
433                         RelativeLayout.SetBottomTarget(itemBadge, itemImage);
434                         RelativeLayout.SetBottomRelativeOffset(itemBadge, 1.0F);
435                         RelativeLayout.SetVerticalAlignment(itemBadge, RelativeLayout.Alignment.End);
436                     }
437                     break;
438             }
439
440
441         }
442
443         /// <summary>
444         /// Initializes AT-SPI object.
445         /// </summary>
446         [EditorBrowsable(EditorBrowsableState.Never)]
447         public override void OnInitialize()
448         {
449             base.OnInitialize();
450             Layout = new RelativeLayout();
451             layoutChanged = true;
452             LayoutDirectionChanged += OnLayoutDirectionChanged;
453         }
454
455         /// <summary>
456         /// Dispose Item and all children on it.
457         /// </summary>
458         /// <param name="type">Dispose type.</param>
459         [EditorBrowsable(EditorBrowsableState.Never)]
460         protected override void Dispose(DisposeTypes type)
461         {
462             if (disposed)
463             {
464                 return;
465             }
466
467             if (type == DisposeTypes.Explicit)
468             {
469                 //Extension : Extension?.OnDispose(this);
470
471                 // Arugable to disposing user-created members.
472                 /*
473                 if (itemBadge != null)
474                 {
475                     Utility.Dispose(itemBadge);
476                 }
477                 */
478
479                 if (itemImage != null)
480                 {
481                     Utility.Dispose(itemImage);
482                     itemImage = null;
483                 }
484                 if (itemLabel != null)
485                 {
486                     Utility.Dispose(itemLabel);
487                     itemLabel = null;
488                 }
489
490             }
491
492             base.Dispose(type);
493         }
494
495         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
496         {
497             MeasureChild();
498             LayoutChild();
499         }
500         private void OnImageRelayout(object sender, EventArgs e)
501         {
502             MeasureChild();
503             LayoutChild();
504         }
505     }
506 }