Support new features of Tizen.CircularUI (#188)
[platform/core/csapi/xsf.git] / src / XSF / Tizen.Wearable.CircularUI.Forms.Renderer / PopupEntryRenderer.cs
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 using ElmSharp;
18 using System;
19 using System.ComponentModel;
20 using Xamarin.Forms;
21 using Xamarin.Forms.Platform.Tizen;
22 using Xamarin.Forms.Platform.Tizen.Native;
23 using EColor = ElmSharp.Color;
24 using ELayout = ElmSharp.Layout;
25 using XForms = Xamarin.Forms.Forms;
26 using XEntry = Xamarin.Forms.Entry;
27
28 [assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.PopupEntry), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.PopupEntryRenderer))]
29
30 namespace Tizen.Wearable.CircularUI.Forms.Renderer
31 {
32         public class PopupEntryRenderer : EntryRenderer
33         {
34                 Background _editorPopup;
35                 EColor _popupBackgroundColor;
36
37                 Xamarin.Forms.Platform.Tizen.Native.Entry _editor;
38
39                 Interop.EFL.InputPanelEventCallback _editorStateChanged;
40
41                 Interop.EFL.InputPanelState _IMEState;
42
43                 EColor DefaultColor { get; set; }
44
45                 bool _IsPopupOpened = false;
46
47                 public PopupEntryRenderer()
48                 {
49                         DefaultColor = new EColor(40, 40, 40, 255); //editfield bg default color
50                         RegisterPropertyHandler(PopupEntry.PopupBackgroundColorProperty, UpdatePopupBackgroundColor);
51                         RegisterPropertyHandler(PopupEntry.IsPopupOpenedProperty, UpdateIsPopupOpened);
52                 }
53
54                 protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Entry> e)
55                 {
56                         base.OnElementChanged(e);
57                         if (e.NewElement != null)
58                         {
59                                 Control.IsEditable = false;
60                                 Control.SetInputPanelEnabled(false);
61                                 Control.Clicked += OnClicked;
62
63                                 // Set Text again for apply text style because IsEditable reset the style of text
64                                 Control.Text = string.Empty;
65                                 Control.Text = Element.Text;
66                         }
67                 }
68
69                 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
70                 {
71                         base.OnElementPropertyChanged(sender, e);
72                         if (_IsPopupOpened && _editor != null)
73                         {
74                                 if (e.PropertyName == XEntry.TextColorProperty.PropertyName ||
75                                         e.PropertyName == XEntry.FontSizeProperty.PropertyName ||
76                                         e.PropertyName == XEntry.FontFamilyProperty.PropertyName ||
77                                         e.PropertyName == XEntry.FontAttributesProperty.PropertyName)
78                                 {
79                                         _editor.TextStyle = Control.TextStyle;
80                                 }
81                         }
82                 }
83
84                 protected override void Dispose(bool disposing)
85                 {
86                         if (disposing)
87                         {
88                                 if (_editor != null)
89                                 {
90                                         IntPtr entryHandle = Interop.EFL.elm_entry_imf_context_get(_editor.RealHandle);
91                                         Interop.EFL.ecore_imf_context_input_panel_event_callback_del(entryHandle, Interop.EFL.InputPanelEventType.State, _editorStateChanged);
92                                 }
93                         }
94                         base.Dispose(disposing);
95                 }
96
97                 void OnClicked(object sender, EventArgs e) => ShowPopup();
98
99                 Window FindWindow(EvasObject obj)
100                 {
101                         EvasObject parent = obj.Parent;
102                         while (!(parent is Window) && parent != null)
103                         {
104                                 parent = parent.Parent;
105                         }
106                         return parent as Window;
107                 }
108
109                 void CreatePopup()
110                 {
111                         var rect = XForms.NativeParent.Geometry;
112
113                         var root = FindWindow(XForms.NativeParent);
114
115                         _editorPopup = new Background(root)
116                         {
117                                 Geometry = rect
118                         };
119
120                         var layout = new ELayout(_editorPopup);
121                         layout.SetTheme("layout", "entry", "default");
122                         layout.Show();
123
124                         _editorPopup.SetPartContent("overlay", layout);
125
126                         _editor = new Xamarin.Forms.Platform.Tizen.Native.Entry(layout);
127                         _editor.IsSingleLine = true;
128                         _editor.Scrollable = true;
129                         _editor.SetInputPanelEnabled(false);
130                         _editor.AllowFocus(true);
131                         _editor.Show();
132
133                         _editor.SetInputPanelReturnKeyType(Element.ReturnType.ToInputPanelReturnKeyType());
134
135                         _editor.UpdateKeyboard(Element.Keyboard, Element.IsSpellCheckEnabled, Element.IsTextPredictionEnabled);
136
137                         _editorPopup.BackButtonPressed += (s, e) => HidePopup();
138
139                         _editor.Activated += (s, e) => HidePopup();
140
141                         IntPtr entryHandle = Interop.EFL.elm_entry_imf_context_get(_editor.RealHandle);
142
143                         _editorStateChanged = EditorStateChanged;
144                         Interop.EFL.ecore_imf_context_input_panel_event_callback_add(entryHandle, Interop.EFL.InputPanelEventType.State, _editorStateChanged, IntPtr.Zero);
145
146                         layout.SetPartContent("elm.swallow.content", _editor);
147                 }
148
149                 void PopupEntryTextChanged(object sender, TextChangedEventArgs e)
150                 {
151                         Control.Text = e.NewTextValue;
152                 }
153
154                 void PopupEntryActivated(object sender, EventArgs e)
155                 {
156                         ((IEntryController)Element).SendCompleted();
157                 }
158
159                 void HidePopup()
160                 {
161                         if (Control is IEntry ie)
162                         {
163                                 ie.TextChanged -= OnTextChanged;
164                         }
165
166                         if (_IMEState != Interop.EFL.InputPanelState.Hide)
167                         {
168                                 _editor.HideInputPanel();
169                         }
170                         else if (_IMEState == Interop.EFL.InputPanelState.Hide)
171                         {
172                                 _editorPopup.Hide();
173                                 _editor.TextChanged -= PopupEntryTextChanged;
174                                 _editor.Activated -= PopupEntryActivated;
175                         }
176                         _IsPopupOpened = false;
177                         ((PopupEntry)Element).IsPopupOpened = false;
178                 }
179
180                 void ShowPopup()
181                 {
182                         if (_editorPopup == null)
183                         {
184                                 CreatePopup();
185                         }
186                         _editor.IsPassword = Control.IsPassword;
187                         if (Control is IEntry ie)
188                         {
189                                 _editor.HorizontalTextAlignment = ie.HorizontalTextAlignment;
190                                 ie.TextChanged += OnTextChanged;
191                         }
192
193                         _editor.Text = Control.Text;
194                         _editor.TextChanged += PopupEntryTextChanged;
195                         _editor.Activated += PopupEntryActivated;
196
197                         _editor.TextStyle = Control.TextStyle;
198                         _editorPopup.Color = _popupBackgroundColor;
199
200                         _editor.MoveCursorEnd();
201                         _editor.ShowInputPanel();
202
203                         _IsPopupOpened = true;
204                         ((PopupEntry)Element).IsPopupOpened = true;
205                 }
206
207                 void EditorStateChanged(IntPtr data, IntPtr ctx, int value)
208                 {
209                         _IMEState = (Interop.EFL.InputPanelState)value;
210                         if (_IMEState == Interop.EFL.InputPanelState.Hide)
211                         {
212                                 HidePopup();
213                         }
214                         else if (_IMEState == Interop.EFL.InputPanelState.Show)
215                         {
216                                 _editor.SetFocus(true);
217                                 _editorPopup.RaiseTop();
218                                 _editorPopup.Show();
219                         }
220                 }
221
222                 void UpdatePopupBackgroundColor()
223                 {
224                         Xamarin.Forms.Color bgColor = ((PopupEntry)Element).PopupBackgroundColor;
225                         if (bgColor == Xamarin.Forms.Color.Default)
226                         {
227                                 _popupBackgroundColor = DefaultColor;
228                         }
229                         else
230                         {
231                                 _popupBackgroundColor = bgColor.ToNative();
232                         }
233
234                         if (_IsPopupOpened == true && _editorPopup != null)
235                         {
236                                 _editorPopup.Color = _popupBackgroundColor;
237                         }
238                 }
239
240                 void OnTextChanged(object sender, EventArgs e)
241                 {
242                         if (_editor != null)
243                         {
244                                 if (_editor.Text != Control.Text)
245                                 {
246                                         _editor.Text = Control.Text;
247                                         if (!_editor.IsFocused)
248                                         {
249                                                 _editor.MoveCursorEnd();
250                                         }
251                                 }
252                         }
253                 }
254
255                 void UpdateIsPopupOpened()
256                 {
257                         bool isOpended = ((PopupEntry)Element).IsPopupOpened;
258                         if (isOpended == _IsPopupOpened)
259                         {
260                                 return;
261                         }
262
263                         _IsPopupOpened = isOpended;
264                         if (isOpended)
265                         {
266                                 ShowPopup();
267                         }
268                         else
269                         {
270                                 HidePopup();
271                         }
272                 }
273         }
274
275         internal static class EntryExtensions
276         {
277                 internal static InputPanelReturnKeyType ToInputPanelReturnKeyType(this ReturnType returnType)
278                 {
279                         switch (returnType)
280                         {
281                                 case ReturnType.Go:
282                                         return InputPanelReturnKeyType.Go;
283                                 case ReturnType.Next:
284                                         return InputPanelReturnKeyType.Next;
285                                 case ReturnType.Send:
286                                         return InputPanelReturnKeyType.Send;
287                                 case ReturnType.Search:
288                                         return InputPanelReturnKeyType.Search;
289                                 case ReturnType.Done:
290                                         return InputPanelReturnKeyType.Done;
291                                 case ReturnType.Default:
292                                         return InputPanelReturnKeyType.Default;
293                                 default:
294                                         throw new NotImplementedException($"ReturnType {returnType} not supported");
295                         }
296                 }
297         }
298 }