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