[NUI] BackKeyEvent Proptotype (#1824)
authorneostom432 <31119276+neostom432@users.noreply.github.com>
Wed, 15 Jul 2020 04:50:05 +0000 (13:50 +0900)
committerGitHub <noreply@github.com>
Wed, 15 Jul 2020 04:50:05 +0000 (13:50 +0900)
View can subscribe back key event using BackKeyEvent event handler.

When user adds BackKeyEvent callback to View, view is listed as Subscriber of BackKeyManager.

After that, if back key is comming,
BackKeyManager will find top view among back key subscribers which has Visibility and IsOnWidnow property are true.

The top view will emit its BackKeyEvent.

*** Notice ***

It is based on Window KeyEvent so make sure you don't use Window KeyEvent and View KeyEvent.

After binding backkey event from DALi, user can use Window/View KeyEvent
with BackKeyEvent.

src/Tizen.NUI/src/internal/BackKeyManager.cs [new file with mode: 0644]
src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs

diff --git a/src/Tizen.NUI/src/internal/BackKeyManager.cs b/src/Tizen.NUI/src/internal/BackKeyManager.cs
new file mode 100644 (file)
index 0000000..0b9b4a7
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright(c) 2020 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
+{
+    /// <summary>
+    /// BackKeyManager is a class to manager back key event.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public sealed class BackKeyManager
+    {
+        private static readonly BackKeyManager instance = new BackKeyManager();
+
+        /// <summary>
+        /// BackKeyManager construct.
+        /// </summary>
+        private BackKeyManager()
+        {
+            NUIApplication.GetDefaultWindow().KeyEvent += OnWindowKeyEvent;
+        }
+
+        /// <summary>
+        /// Subscriber.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public List<View> Subscriber{get; set;} = new List<View>();
+
+        /// <summary>
+        /// BackKeyManager static instance.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static BackKeyManager Instance { get { return instance; } }
+
+        private Container FindParent(Container child, int step)
+        {
+            Container result = child;
+
+            for (int i = 0; i < step; i++)
+            {
+                result = result?.GetParent();
+            }
+
+            return result;
+        }
+
+        // If false, comparison1 is on top and if true, comparison2 is on top.
+        private bool CompareElevation(Container comparison1, Container comparison2)
+        {
+            bool result = false;
+
+            Container parent1 = comparison1?.GetParent();
+            Container parent2 = comparison2?.GetParent();
+
+            if((parent1 == null && parent2 != null) || (parent2 == null && parent1 != null))
+            {
+                // One is in DefaultLayer but the other is not
+                if(parent2 == null)
+                {
+                    // parent1 is in DefaultLayer.
+                    Layer comparison2AsLayer = comparison2 as Layer;
+                    result = comparison2AsLayer.Depth > NUIApplication.GetDefaultWindow().GetDefaultLayer().Depth;
+                }
+                else
+                {
+                    // parent2 is in DefaultLayer.
+                    Layer comparison1AsLayer = comparison1 as Layer;
+                    result = NUIApplication.GetDefaultWindow().GetDefaultLayer().Depth < comparison1AsLayer.Depth;
+                }
+            }
+            else
+            {
+                // If they have same parent, ready to compare!
+                if(parent1 == parent2)
+                {
+
+                    if(comparison1.GetType().FullName.Contains("Layer"))
+                    {
+                        // If comparison1 is Layer, comparison2 is also Layer because only window can have Layer as child in NUI.
+                        // Compare Depth
+                        Layer comparison1AsLayer = comparison1 as Layer;
+                        Layer comparison2AsLayer = comparison2 as Layer;
+
+                        result = comparison1AsLayer.Depth < comparison2AsLayer.Depth;
+                    }
+                    else
+                    {
+                        // If comparison1 is View, comparison2 is also View because only window can have Layer as child in NUI.
+                        // Compare SiblingOrder
+                        View comparison1AsView = comparison1 as View;
+                        View comparison2AsView = comparison2 as View;
+
+                        result = comparison1AsView.SiblingOrder < comparison2AsView.SiblingOrder;
+                    }
+                }
+                else
+                {
+                    // Check ancestor
+                    result = CompareElevation(parent1, parent2);
+                }
+            }
+
+            return result;
+        }
+
+        private void OnWindowKeyEvent(object source, Window.KeyEventArgs args)
+        {
+            if(args.Key.State == Key.StateType.Up && args.Key.KeyPressedName == "Back")
+            {
+                View top = null;
+
+                for (int i = 0; i < Subscriber.Count; i++)
+                {
+                    // Check visibility
+                    if(Subscriber[i].Visibility && Subscriber[i].IsOnWindow)
+                    {
+                        // Initialize first top
+                        if(top == null)
+                        {
+                            top = Subscriber[i];
+                            continue;
+                        }
+                        else
+                        {
+                            if(top.HierarchyDepth != Subscriber[i].HierarchyDepth)
+                            {
+                                Container compare1 = top;
+                                Container compare2 = Subscriber[i];
+
+                                // If their depth is different, sync.
+                                if(top.HierarchyDepth > Subscriber[i].HierarchyDepth)
+                                {
+                                    compare1 = FindParent(compare1, top.HierarchyDepth - Subscriber[i].HierarchyDepth);
+                                }
+                                else
+                                {
+                                    compare2 = FindParent(compare2, Subscriber[i].HierarchyDepth - top.HierarchyDepth);
+                                }
+
+                                if(compare1 == compare2)
+                                {
+                                    // One is descendant of the other. Descendant is above ancestor.
+                                    top = top.HierarchyDepth > Subscriber[i].HierarchyDepth? top : Subscriber[i];
+                                }
+                                else
+                                {
+                                    // Need to compare.
+                                    top = CompareElevation(compare1, compare2) ? Subscriber[i] : top;
+                                }
+                            }
+                            else
+                            {
+                                top = CompareElevation(top, Subscriber[i]) ? Subscriber[i] : top;
+                            }
+                        }
+                    }
+                }
+
+                top?.EmitBackKeyPressed();
+            }
+        }
+    }
+}
index e587b2b..ec8f48c 100755 (executable)
@@ -462,6 +462,38 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        private EventHandler _backKeyPressed;
+
+        /// <summary>
+        /// An event for getting notice when physical back key is pressed.<br />
+        /// This event is emitted BackKey is up.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public event EventHandler BackKeyPressed
+        {
+            add
+            {
+                _backKeyPressed += value;
+                BackKeyManager.Instance.Subscriber.Add(this);
+            }
+
+            remove
+            {
+                BackKeyManager.Instance.Subscriber.Remove(this);
+                _backKeyPressed -= value;
+            }
+        }
+
+        /// <summary>
+        /// Function for emitting BackKeyPressed event outside of View instance
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal void EmitBackKeyPressed()
+        {
+            _backKeyPressed.Invoke(this,null);
+        }
+
+
         internal event EventHandler<BackgroundResourceLoadedEventArgs> BackgroundResourceLoaded
         {
             add