/* * Copyright(c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.ComponentModel; using System.Collections.Generic; using Tizen.NUI.BaseComponents; namespace Tizen.NUI.Components { /// /// AlertDialog class shows a dialog with title, message and action buttons. /// /// 9 public class AlertDialog : Control { private string title = null; private string message = null; private View titleContent = null; private View content = null; private View actionContent = null; private IEnumerable actionContentViews = null; private View defaultTitleContent = null; private View defaultContent = null; private View defaultActionContent = null; // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly. // Until the bug is fixed, padding view is added after action content. private View defaultActionContentPadding = null; private bool styleApplied = false; /// /// Creates a new instance of AlertDialog. /// /// 9 public AlertDialog() : base() { Initialize(); } /// /// Creates a new instance of AlertDialog. /// /// Creates AlertDialog by special style defined in UX. /// 9 public AlertDialog(string style) : base(style) { Initialize(); } /// /// Creates a new instance of AlertDialog. /// /// Creates AlertDialog by style customized by user. /// 9 public AlertDialog(AlertDialogStyle alertDialogStyle) : base(alertDialogStyle) { Initialize(); } /// [EditorBrowsable(EditorBrowsableState.Never)] protected override void Dispose(DisposeTypes type) { if (disposed) { return; } if (type == DisposeTypes.Explicit) { if (titleContent != null) { Utility.Dispose(titleContent); } if (content != null) { Utility.Dispose(content); } if (actionContent != null) { Utility.Dispose(actionContent); } // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly. // Until the bug is fixed, padding view is added after action content. if (defaultActionContentPadding != null) { Utility.Dispose(defaultActionContentPadding); } } base.Dispose(type); } /// /// Applies style to AlertDialog. /// /// The style to apply. /// 9 public override void ApplyStyle(ViewStyle viewStyle) { styleApplied = false; base.ApplyStyle(viewStyle); var alertDialogStyle = viewStyle as AlertDialogStyle; if (alertDialogStyle == null) { return; } // Apply Title style. if ((alertDialogStyle.TitleTextLabel != null) && (DefaultTitleContent is TextLabel)) { ((TextLabel)DefaultTitleContent)?.ApplyStyle(alertDialogStyle.TitleTextLabel); } // Apply Message style. if ((alertDialogStyle.MessageTextLabel != null) && (DefaultContent is TextLabel)) { ((TextLabel)DefaultContent)?.ApplyStyle(alertDialogStyle.MessageTextLabel); } // Apply ActionContent style. if (alertDialogStyle.ActionContent != null) { DefaultActionContent?.ApplyStyle(alertDialogStyle.ActionContent); } styleApplied = true; // Calculate dialog position and children's positions based on padding sizes. CalculatePosition(); } /// /// Title text of AlertDialog. /// Title text is set to TitleContent's Text if TitleContent is TextLabel. /// If TitleContent's Text is set manually by user, then it is not guaranteed that TitleContent's Text is the same with Title text. /// /// 9 public string Title { get { return title; } set { if (title == value) { return; } title = value; if (TitleContent is TextLabel textLabel) { textLabel.Text = title; } } } /// /// Title content of AlertDialog. /// TitleContent is added as a child of AlertDialog automatically. /// Title text is set to TitleContent's Text if TitleContent is TextLabel. /// If TitleContent's Text is set manually by user, then it is not guaranteed that TitleContent's Text is the same with Title text. /// /// 9 public View TitleContent { get { return titleContent; } set { if (titleContent == value) { return; } if (titleContent != null) { Remove(titleContent); } titleContent = value; if (titleContent == null) { return; } if (titleContent is TextLabel textLabel) { textLabel.Text = Title; } ResetContent(); } } /// /// Message text of AlertDialog. /// Message text is set to Content's Text if Content is TextLabel. /// If Content's Text is set manually by user, then it is not guaranteed that Content's Text is the same with Message text. /// /// 9 public string Message { get { return message; } set { if (message == value) { return; } message = value; if (Content is TextLabel textLabel) { textLabel.Text = message; } } } /// /// Content of AlertDialog. /// Content is added as a child of AlertDialog automatically. /// Message text is set to Content's Text if Content is TextLabel. /// If Content's Text is set manually by user, then it is not guaranteed that Content's Text is the same with Message text. /// /// 9 public View Content { get { return content; } set { if (content == value) { return; } if (content != null) { Remove(content); } content = value; if (content == null) { return; } if (content is TextLabel textLabel) { textLabel.Text = message; } ResetContent(); } } /// /// Action views of AlertDialog. /// Action views are added as children of ActionContent. /// When Actions are set, previous Actions are removed from ActionContent. /// /// 9 public IEnumerable Actions { get { return actionContentViews; } set { if (ActionContent == null) { actionContentViews = value; return; } if (actionContentViews != null) { foreach (var oldAction in actionContentViews) { if (ActionContent.Children?.Contains(oldAction) == true) { ActionContent.Children.Remove(oldAction); } } } actionContentViews = value; if (actionContentViews == null) { return; } foreach (var action in actionContentViews) { ActionContent.Add(action); } } } /// /// Action content of AlertDialog. /// ActionContent is added as a child of AlertDialog automatically. /// Actions are added as children of ActionContent. /// /// 9 public View ActionContent { get { return actionContent; } set { if (actionContent == value) { return; } var oldActionContent = actionContent; actionContent = value; // Add views first before remove previous action content // not to cause Garbage Collector collects views. if ((actionContent != null) && (Actions != null)) { foreach (var action in Actions) { actionContent.Add(action); } } if (oldActionContent != null) { Remove(oldActionContent); } if (actionContent == null) { return; } ResetContent(); } } /// /// AccessibilityGetName. /// [EditorBrowsable(EditorBrowsableState.Never)] protected override string AccessibilityGetName() { if (!String.IsNullOrEmpty(Title)) { return Title; } else { return Message; } } /// /// Initialize AT-SPI object. /// [EditorBrowsable(EditorBrowsableState.Never)] public override void OnInitialize() { base.OnInitialize(); SetAccessibilityConstructor(Role.Dialog); AppendAccessibilityAttribute("sub-role", "Alert"); Show(); // calls AddPopup() } /// /// Informs AT-SPI bridge about the set of AT-SPI states associated with this object. /// [EditorBrowsable(EditorBrowsableState.Never)] protected override AccessibilityStates AccessibilityCalculateStates() { var states = base.AccessibilityCalculateStates(); FlagSetter(ref states, AccessibilityStates.Modal, true); return states; } /// /// Default title content of AlertDialog. /// If Title is set, then default title content is automatically displayed. /// [EditorBrowsable(EditorBrowsableState.Never)] protected View DefaultTitleContent { get { if (defaultTitleContent == null) { defaultTitleContent = CreateDefaultTitleContent(); } return defaultTitleContent; } } /// /// Default content of AlertDialog. /// If Message is set, then default content is automatically displayed. /// [EditorBrowsable(EditorBrowsableState.Never)] protected View DefaultContent { get { if (defaultContent == null) { defaultContent = CreateDefaultContent(); } return defaultContent; } } /// /// Default action content of AlertDialog. /// If Actions are set, then default action content is automatically displayed. /// [EditorBrowsable(EditorBrowsableState.Never)] protected View DefaultActionContent { get { if (defaultActionContent == null) { defaultActionContent = CreateDefaultActionContent(); } // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly. // Until the bug is fixed, padding view is added after action content. if (defaultActionContentPadding == null) { defaultActionContentPadding = CreateDefaultActionContentPadding(); } return defaultActionContent; } } private void Initialize() { Layout = new LinearLayout() { LinearOrientation = LinearLayout.Orientation.Vertical, LinearAlignment = LinearLayout.Alignment.CenterHorizontal, }; this.Relayout += OnRelayout; TitleContent = DefaultTitleContent; Content = DefaultContent; ActionContent = DefaultActionContent; } private void ResetContent() { //To keep the order of TitleContent, Content and ActionContent, //the existing contents are removed and added again. if (titleContent != null) { Remove(titleContent); } if (content != null) { Remove(content); } if (actionContent != null) { Remove(actionContent); } if (titleContent != null) { Add(titleContent); } if (content != null) { Add(content); } if (actionContent != null) { Add(actionContent); // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly. // Until the bug is fixed, padding view is added after action content. if (actionContent == defaultActionContent) { if (defaultActionContentPadding != null) { Add(defaultActionContentPadding); } } } } private TextLabel CreateDefaultTitleContent() { return new TextLabel(); } private TextLabel CreateDefaultContent() { return new TextLabel(); } private View CreateDefaultActionContent() { return new View() { Layout = new LinearLayout() { LinearOrientation = LinearLayout.Orientation.Horizontal, LinearAlignment = LinearLayout.Alignment.Center, // FIXME: This CellPadding value should be written in AlertDialogStyle. // However, if this is called in other place, then flicking issue happens. CellPadding = new Size2D(80, 0), }, }; } // FIXME: Now AlertDialog.Padding Top and Bottom increases AlertDialog size incorrectly. // Until the bug is fixed, padding view is added after action content. private View CreateDefaultActionContentPadding() { var layout = Layout as LinearLayout; if ((layout == null) || (defaultActionContent == null)) { return null; } View paddingView = null; using (Size2D size = new Size2D(defaultActionContent.Size2D.Width, defaultActionContent.Size2D.Height)) { if (layout.LinearOrientation == LinearLayout.Orientation.Horizontal) { size.Width = 40; } else { size.Height = 40; } paddingView = new View() { Size2D = new Size2D(size.Width, size.Height), }; } return paddingView; } private void OnRelayout(object sender, EventArgs e) { // Calculate dialog position and children's positions based on padding sizes. CalculatePosition(); } // Calculate dialog position and children's positions based on padding sizes. private void CalculatePosition() { if (styleApplied == false) { return; } var size = Size2D; var parent = GetParent(); Size2D parentSize; if ((parent != null) && (parent is View)) { parentSize = ((View)parent).Size; } else { parentSize = NUIApplication.GetDefaultWindow().Size; } Position2D = new Position2D((parentSize.Width - size.Width) / 2, (parentSize.Height - size.Height) / 2); } } }