b1b3ee58e53f5a3cdc1a34c88033d95919e09fd1
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / AlertDialog.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.ComponentModel;
20 using System.Collections.Generic;
21 using Tizen.NUI.BaseComponents;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// AlertDialog class shows a dialog with title, message and action buttons.
27     /// </summary>
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public class AlertDialog : Control
30     {
31         private string title = null;
32         private string message = null;
33
34         private View titleContent = null;
35         private View content = null;
36         private View actionContent = null;
37         private IEnumerable<View> actionContentViews = null;
38
39         private View defaultTitleContent = null;
40         private View defaultContent = null;
41         private View defaultActionContent = null;
42         // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly.
43         //        Until the bug is fixed, padding view is added after action content.
44         private View defaultActionContentPadding = null;
45
46         private AlertDialogStyle alertDialogStyle => ViewStyle as AlertDialogStyle;
47
48         private bool styleApplied = false;
49
50         /// <summary>
51         /// Creates a new instance of AlertDialog.
52         /// </summary>
53         [EditorBrowsable(EditorBrowsableState.Never)]
54         public AlertDialog() : base()
55         {
56             Initialize();
57         }
58
59         /// <summary>
60         /// Dispose AlertDialog and all children on it.
61         /// </summary>
62         /// <param name="type">Dispose type.</param>
63         [EditorBrowsable(EditorBrowsableState.Never)]
64         protected override void Dispose(DisposeTypes type)
65         {
66             if (disposed)
67             {
68                 return;
69             }
70
71             if (type == DisposeTypes.Explicit)
72             {
73                 if (titleContent != null)
74                 {
75                     Utility.Dispose(titleContent);
76                 }
77
78                 if (content != null)
79                 {
80                     Utility.Dispose(content);
81                 }
82
83                 if (actionContent != null)
84                 {
85                     Utility.Dispose(actionContent);
86                 }
87
88                 // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly.
89                 //        Until the bug is fixed, padding view is added after action content.
90                 if (defaultActionContentPadding != null)
91                 {
92                     Utility.Dispose(defaultActionContentPadding);
93                 }
94             }
95
96             base.Dispose(type);
97         }
98
99         /// <summary>
100         /// Applies style to AlertDialog.
101         /// </summary>
102         /// <param name="viewStyle">The style to apply.</param>
103         [EditorBrowsable(EditorBrowsableState.Never)]
104         public override void ApplyStyle(ViewStyle viewStyle)
105         {
106             styleApplied = false;
107
108             base.ApplyStyle(viewStyle);
109
110             // Apply Title style.
111             if ((alertDialogStyle?.TitleTextLabel != null) && (DefaultTitleContent is TextLabel))
112             {
113                 ((TextLabel)DefaultTitleContent)?.ApplyStyle(alertDialogStyle.TitleTextLabel);
114             }
115
116             // Apply Message style.
117             if ((alertDialogStyle?.MessageTextLabel != null) && (DefaultContent is TextLabel))
118             {
119                 ((TextLabel)DefaultContent)?.ApplyStyle(alertDialogStyle.MessageTextLabel);
120             }
121
122             // Apply ActionContent style.
123             if (alertDialogStyle?.ActionContent != null)
124             {
125                 DefaultActionContent?.ApplyStyle(alertDialogStyle.ActionContent);
126             }
127
128             styleApplied = true;
129
130             // Calculate dialog position and children's positions based on padding sizes.
131             CalculatePosition();
132         }
133
134         /// <summary>
135         /// Title text of AlertDialog.
136         /// </summary>
137         [EditorBrowsable(EditorBrowsableState.Never)]
138         public string Title
139         {
140             get
141             {
142                 return title;
143             }
144             set
145             {
146                 if (title == value)
147                 {
148                     return;
149                 }
150
151                 title = value;
152
153                 if (TitleContent is TextLabel textLabel)
154                 {
155                     textLabel.Text = title;
156                 }
157             }
158         }
159
160         /// <summary>
161         /// Title content of AlertDialog. TitleContent is added to Children automatically.
162         /// </summary>
163         [EditorBrowsable(EditorBrowsableState.Never)]
164         public View TitleContent
165         {
166             get
167             {
168                 return titleContent;
169             }
170             set
171             {
172                 if (titleContent == value)
173                 {
174                     return;
175                 }
176
177                 if (titleContent != null)
178                 {
179                     Remove(titleContent);
180                 }
181
182                 titleContent = value;
183                 if (titleContent == null)
184                 {
185                     return;
186                 }
187
188                 if (titleContent is TextLabel textLabel)
189                 {
190                     textLabel.Text = Title;
191                 }
192
193                 ResetContent();
194             }
195         }
196
197         /// <summary>
198         /// Message text of AlertDialog.
199         /// </summary>
200         [EditorBrowsable(EditorBrowsableState.Never)]
201         public string Message
202         {
203             get
204             {
205                 return message;
206             }
207             set
208             {
209                 if (message == value)
210                 {
211                     return;
212                 }
213
214                 message = value;
215
216                 if (Content is TextLabel textLabel)
217                 {
218                     textLabel.Text = message;
219                 }
220             }
221         }
222
223         /// <summary>
224         /// Content of AlertDialog. Content is added to Children automatically.
225         /// </summary>
226         [EditorBrowsable(EditorBrowsableState.Never)]
227         public View Content
228         {
229             get
230             {
231                 return content;
232             }
233             set
234             {
235                 if (content == value)
236                 {
237                     return;
238                 }
239
240                 if (content != null)
241                 {
242                     Remove(content);
243                 }
244
245                 content = value;
246                 if (content == null)
247                 {
248                     return;
249                 }
250
251                 if (content is TextLabel textLabel)
252                 {
253                     textLabel.Text = message;
254                 }
255
256                 ResetContent();
257             }
258         }
259
260         /// <summary>
261         /// Action views of AlertDialog.
262         /// Action views are added to ActionContent of AlertDialog.
263         /// </summary>
264         [EditorBrowsable(EditorBrowsableState.Never)]
265         public IEnumerable<View> Actions
266         {
267             get
268             {
269                 return actionContentViews;
270             }
271             set
272             {
273                 if (ActionContent == null)
274                 {
275                     actionContentViews = value;
276                     return;
277                 }
278
279                 if (actionContentViews != null)
280                 {
281                     foreach (var oldAction in actionContentViews)
282                     {
283                         if (ActionContent.Children?.Contains(oldAction) == true)
284                         {
285                             ActionContent.Children.Remove(oldAction);
286                         }
287                     }
288                 }
289
290                 actionContentViews = value;
291
292                 if (actionContentViews == null)
293                 {
294                     return;
295                 }
296
297                 foreach (var action in actionContentViews)
298                 {
299                     ActionContent.Add(action);
300                 }
301             }
302         }
303
304         /// <summary>
305         /// Action content of AlertDialog. ActionContent is added to Children automatically.
306         /// </summary>
307         [EditorBrowsable(EditorBrowsableState.Never)]
308         public View ActionContent
309         {
310              get
311              {
312                 return actionContent;
313              }
314              set
315              {
316                 if (actionContent == value)
317                  {
318                      return;
319                  }
320
321                 var oldActionContent = actionContent;
322                 actionContent = value;
323
324                 // Add views first before remove previous action content
325                 // not to cause Garbage Collector collects views.
326                 if ((actionContent != null) && (Actions != null))
327                 {
328                     foreach (var action in Actions)
329                     {
330                         actionContent.Add(action);
331                     }
332                 }
333
334                 if (oldActionContent != null)
335                 {
336                     Remove(oldActionContent);
337                 }
338
339                 if (actionContent == null)
340                 {
341                     return;
342                 }
343
344                 ResetContent();
345             }
346         }
347
348         /// <summary>
349         /// AccessibilityGetName.
350         /// </summary>
351         [EditorBrowsable(EditorBrowsableState.Never)]
352         protected override string AccessibilityGetName()
353         {
354             if (!String.IsNullOrEmpty(Title))
355             {
356                 return Title;
357             }
358             else
359             {
360                 return Message;
361             }
362         }
363
364         /// <summary>
365         /// Default title content of AlertDialog.
366         /// If Title is set, then default title content is automatically displayed.
367         /// </summary>
368         [EditorBrowsable(EditorBrowsableState.Never)]
369         protected View DefaultTitleContent
370         {
371             get
372             {
373                 if (defaultTitleContent == null)
374                 {
375                     defaultTitleContent = CreateDefaultTitleContent();
376                 }
377
378                 return defaultTitleContent;
379             }
380         }
381
382         /// <summary>
383         /// Default content of AlertDialog.
384         /// If Message is set, then default content is automatically displayed.
385         /// </summary>
386         [EditorBrowsable(EditorBrowsableState.Never)]
387         protected View DefaultContent
388         {
389             get
390             {
391                 if (defaultContent == null)
392                 {
393                     defaultContent = CreateDefaultContent();
394                 }
395
396                 return defaultContent;
397             }
398         }
399
400         /// <summary>
401         /// Default action content of AlertDialog.
402         /// If Actions are set, then default action content is automatically displayed.
403         /// </summary>
404         [EditorBrowsable(EditorBrowsableState.Never)]
405         protected View DefaultActionContent
406         {
407             get
408             {
409                 if (defaultActionContent == null)
410                 {
411                     defaultActionContent = CreateDefaultActionContent();
412                 }
413
414                 // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly.
415                 //        Until the bug is fixed, padding view is added after action content.
416                 if (defaultActionContentPadding == null)
417                 {
418                     defaultActionContentPadding = CreateDefaultActionContentPadding();
419                 }
420
421                 return defaultActionContent;
422             }
423         }
424
425         private void Initialize()
426         {
427             Layout = new LinearLayout()
428             {
429                 LinearOrientation = LinearLayout.Orientation.Vertical,
430             };
431
432             this.Relayout += OnRelayout;
433
434             TitleContent = DefaultTitleContent;
435
436             Content = DefaultContent;
437
438             ActionContent = DefaultActionContent;
439         }
440
441         private void ResetContent()
442         {
443             //To keep the order of TitleContent, Content and ActionContent,
444             //the existing contents are removed and added again.
445             if (titleContent != null)
446             {
447                 Remove(titleContent);
448             }
449
450             if (content != null)
451             {
452                 Remove(content);
453             }
454
455             if (actionContent != null)
456             {
457                 Remove(actionContent);
458             }
459
460             if (titleContent != null)
461             {
462                 Add(titleContent);
463             }
464
465             if (content != null)
466             {
467                 Add(content);
468             }
469
470             if (actionContent != null)
471             {
472                 Add(actionContent);
473
474                 // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly.
475                 //        Until the bug is fixed, padding view is added after action content.
476                 if (actionContent == defaultActionContent)
477                 {
478                     if (defaultActionContentPadding != null)
479                     {
480                         Add(defaultActionContentPadding);
481                     }
482                 }
483             }
484         }
485
486         private TextLabel CreateDefaultTitleContent()
487         {
488             return new TextLabel();
489         }
490
491         private TextLabel CreateDefaultContent()
492         {
493             return new TextLabel();
494         }
495
496         private View CreateDefaultActionContent()
497         {
498             return new View()
499             {
500                 Layout = new LinearLayout()
501                 {
502                     LinearOrientation = LinearLayout.Orientation.Horizontal,
503                 },
504             };
505         }
506
507         // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly.
508         //        Until the bug is fixed, padding view is added after action content.
509         private View CreateDefaultActionContentPadding()
510         {
511             var layout = Layout as LinearLayout;
512
513             if ((layout == null) || (defaultActionContent == null))
514             {
515                 return null;
516             }
517
518             View paddingView = null;
519
520             using (Size2D size = new Size2D(defaultActionContent.Size2D.Width, defaultActionContent.Size2D.Height))
521             {
522                 if (layout.LinearOrientation == LinearLayout.Orientation.Horizontal)
523                 {
524                     size.Width = 40;
525                 }
526                 else
527                 {
528                     size.Height = 40;
529                 }
530
531                 paddingView = new View()
532                 {
533                     Size2D = new Size2D(size.Width, size.Height),
534                 };
535             }
536
537             return paddingView;
538         }
539
540         private void OnRelayout(object sender, EventArgs e)
541         {
542             // Calculate dialog position and children's positions based on padding sizes.
543             CalculatePosition();
544         }
545
546         // Calculate dialog position and children's positions based on padding sizes.
547         private void CalculatePosition()
548         {
549             if (styleApplied == false)
550             {
551                 return;
552             }
553
554             CalculateActionsCellPadding();
555
556             var size = Size2D;
557             var parent = GetParent();
558             Size2D parentSize;
559
560             if ((parent != null) && (parent is View))
561             {
562                 parentSize = ((View)parent).Size;
563             }
564             else
565             {
566                 parentSize = NUIApplication.GetDefaultWindow().Size;
567             }
568
569             Position2D = new Position2D((parentSize.Width - size.Width) / 2, (parentSize.Height - size.Height) / 2);
570         }
571
572         // Calculate CellPadding among Actions if ActionContent is LinearLayout.
573         private void CalculateActionsCellPadding()
574         {
575             if ((ActionContent != DefaultActionContent) || (ActionContent.Layout is LinearLayout == false))
576             {
577                 return;
578             }
579
580             if (Actions == null)
581             {
582                 return;
583             }
584
585             var size = Size2D;
586             var layout = ActionContent.Layout as LinearLayout;
587             int count = 0;
588
589             if (layout.LinearOrientation == LinearLayout.Orientation.Horizontal)
590             {
591                 int actionsWidth = 0;
592
593                 foreach (var action in Actions)
594                 {
595                     actionsWidth += ((View)action).Size2D.Width + ((((View)action).Margin?.Start + ((View)action).Margin?.End) ?? 0);
596                     count++;
597                 }
598
599                 if (count > 1)
600                 {
601                     actionsWidth += (Padding?.Start + Padding?.End) ?? 0;
602                     var cellPaddingWidth = (size.Width - actionsWidth) / (count - 1);
603                     layout.CellPadding = new Size2D(cellPaddingWidth , 0);
604                 }
605             }
606             else
607             {
608                 int actionsHeight = 0;
609
610                 foreach (var action in Actions)
611                 {
612                     actionsHeight += ((View)action).Size2D.Height + ((((View)action).Margin?.Top + ((View)action).Margin?.Bottom) ?? 0);
613                     count++;
614                 }
615
616                 if (count > 1)
617                 {
618                     actionsHeight += (Padding?.Top + Padding?.Bottom) ?? 0;
619                     var cellPaddingHeight = (size.Height - actionsHeight) / (count - 1);
620                     layout.CellPadding = new Size2D(0, cellPaddingHeight);
621                 }
622             }
623         }
624     }
625 }