Add BackButtonPressed/MoreButtonPressed event on EvasObject
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / EvasObject.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Generic;
19 using System.Diagnostics;
20
21 namespace ElmSharp
22 {
23     /// <summary>
24     /// The EcasObject is a base class for other widget class
25     /// </summary>
26     public abstract class EvasObject
27     {
28         private IntPtr _realHandle = IntPtr.Zero;
29         private event EventHandler _backButtonPressed;
30         private event EventHandler _moreButtonPressed;
31         private Interop.Eext.EextEventCallback _backButtonHandler;
32         private Interop.Eext.EextEventCallback _moreButtonHandler;
33
34         internal IntPtr Handle { get; set; }
35         internal EvasObject Parent { get; set; }
36         internal IntPtr RealHandle
37         {
38             get
39             {
40                 return _realHandle == IntPtr.Zero ? Handle : _realHandle;
41             }
42             set
43             {
44                 _realHandle = value;
45             }
46         }
47
48         EvasObjectEvent _deleted;
49         EvasObjectEvent<EvasKeyEventArgs> _keyup;
50         EvasObjectEvent<EvasKeyEventArgs> _keydown;
51         EvasObjectEvent _moved;
52         EvasObjectEvent _resized;
53         EventHandler _renderPost;
54         Interop.Evas.EvasCallback _renderPostCallback = null;
55
56         readonly HashSet<IInvalidatable> _eventStore = new HashSet<IInvalidatable>();
57
58         /// <summary>
59         /// Creates and initializes a new instance of the EvasObject class with parent EvasObject class parameter.
60         /// </summary>
61         /// <param name="parent">Parent EvasObject class </param>
62         protected EvasObject(EvasObject parent) : this()
63         {
64             Debug.Assert(parent == null || parent.IsRealized);
65             Realize(parent);
66         }
67
68         /// <summary>
69         /// Creates and initializes a new instance of the EvasObject class.
70         /// </summary>
71         protected EvasObject()
72         {
73             _backButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _backButtonPressed?.Invoke(this, EventArgs.Empty); });
74             _moreButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _moreButtonPressed?.Invoke(this, EventArgs.Empty); });
75
76             OnInstantiated();
77         }
78
79         // C# Finalizer was called on GC thread
80         // So, We can't access to EFL object
81         // And When Finalizer was called, Field can be already released.
82         //~EvasObject()
83         //{
84         //    Unrealize();
85         //}
86
87         /// <summary>
88         /// Deleted will be triggered when widght is deleted
89         /// </summary>
90         public event EventHandler Deleted;
91         /// <summary>
92         /// KeyUp will be triggered when key is loose
93         /// </summary>
94         public event EventHandler<EvasKeyEventArgs> KeyUp;
95         /// <summary>
96         /// KeyDown will be triggered when key is preesd down
97         /// </summary>
98         public event EventHandler<EvasKeyEventArgs> KeyDown;
99
100         /// <summary>
101         /// BackButtonPressed will be triggered when Back button is pressed
102         /// </summary>
103         public event EventHandler BackButtonPressed
104         {
105             add
106             {
107                 if (_backButtonPressed == null)
108                 {
109                     Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler, IntPtr.Zero);
110                 }
111                 _backButtonPressed += value;
112             }
113             remove
114             {
115                 _backButtonPressed -= value;
116                 if (_backButtonPressed == null)
117                 {
118                     Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler);
119                 }
120             }
121         }
122
123         /// <summary>
124         /// MoreButtonPressed will be triggered when More button is pressed
125         /// </summary>
126         public event EventHandler MoreButtonPressed
127         {
128             add
129             {
130                 if (_moreButtonPressed == null)
131                 {
132                     Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler, IntPtr.Zero);
133                 }
134                 _moreButtonPressed += value;
135             }
136             remove
137             {
138                 _moreButtonPressed -= value;
139                 if (_moreButtonPressed == null)
140                 {
141                     Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler);
142                 }
143             }
144         }
145
146
147         /// <summary>
148         /// Moved will be triggered when widght is moved
149         /// </summary>
150         public event EventHandler Moved
151         {
152             add { _moved.On += value; }
153             remove { _moved.On -= value; }
154         }
155         /// <summary>
156         /// Current widget's size Resized Event Handler
157         /// </summary>
158         public event EventHandler Resized
159         {
160             add { _resized.On += value; }
161             remove { _resized.On -= value; }
162         }
163
164         /// <summary>
165         /// Current widget RenderPost Event Handler
166         /// </summary>
167         public event EventHandler RenderPost
168         {
169             add
170             {
171                 _renderPost += value;
172                 if (_renderPostCallback == null)
173                 {
174                     _renderPostCallback = new Interop.Evas.EvasCallback((o, e, d) => _renderPost?.Invoke(this, EventArgs.Empty));
175                     Interop.Evas.evas_event_callback_add(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback, IntPtr.Zero);
176                 }
177             }
178             remove
179             {
180                 _renderPost -= value;
181                 if (_renderPost?.GetInvocationList().Length == 0)
182                 {
183                     Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback);
184                     _renderPostCallback = null;
185                 }
186             }
187         }
188
189         /// <summary>
190         /// Get widget's status of Realized or not.
191         /// </summary>
192         public bool IsRealized { get { return Handle != IntPtr.Zero; } }
193
194         /// <summary>
195         /// Gets the current class's Name.
196         /// </summary>
197         public string ClassName
198         {
199             get
200             {
201                 return Interop.Eo.eo_class_name_get(Interop.Eo.eo_class_get(RealHandle));
202             }
203         }
204
205         /// <summary>
206         /// Sets or gets the horizontal pointer hints for an object's weight.
207         /// </summary>
208         public double WeightX
209         {
210             get
211             {
212                 return Interop.Evas.GetWeightX(Handle);
213             }
214             set
215             {
216                 Interop.Evas.SetWeightX(Handle, value);
217             }
218         }
219
220         /// <summary>
221         /// Sets or gets the vertical pointer hints for an object's weight.
222         /// </summary>
223         public double WeightY
224         {
225             get
226             {
227                 return Interop.Evas.GetWeightY(Handle);
228             }
229             set
230             {
231                 Interop.Evas.SetWeightY(Handle, value);
232             }
233         }
234
235         /// <summary>
236         /// Sets or gets the horizontal alignment hint of an object's alignment.
237         /// </summary>
238         public virtual double AlignmentX
239         {
240             get
241             {
242                 return Interop.Evas.GetAlignX(Handle);
243             }
244             set
245             {
246                 Interop.Evas.SetAlignX(Handle, value);
247             }
248         }
249
250         /// <summary>
251         /// Sets or gets the vertical alignment hint of an object's alignment.
252         /// </summary>
253         public virtual double AlignmentY
254         {
255             get
256             {
257                 return Interop.Evas.GetAlignY(Handle);
258             }
259             set
260             {
261                 Interop.Evas.SetAlignY(Handle, value);
262             }
263         }
264
265         /// <summary>
266         /// Sets or gets the Width hints for an object's minimum size.
267         /// </summary>
268         public int MinimumWidth
269         {
270             get
271             {
272                 int w, h;
273                 Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h);
274                 return w;
275             }
276             set
277             {
278                 int h = MinimumHeight;
279                 Interop.Evas.evas_object_size_hint_min_set(RealHandle, value, h);
280             }
281         }
282
283         /// <summary>
284         /// Sets or gets the Height hints for an object's minimum size.
285         /// </summary>
286         public int MinimumHeight
287         {
288             get
289             {
290                 int w, h;
291                 Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h);
292                 return h;
293             }
294             set
295             {
296                 int w = MinimumWidth;
297                 Interop.Evas.evas_object_size_hint_min_set(RealHandle, w, value);
298             }
299         }
300
301         /// <summary>
302         /// Gets the visible state of the given Evas object.
303         /// </summary>
304         public bool IsVisible
305         {
306             get
307             {
308                 return Interop.Evas.evas_object_visible_get(Handle);
309             }
310         }
311
312         /// <summary>
313         /// Sets or gets the position and (rectangular) size of the given Evas object.
314         /// </summary>
315         public Rect Geometry
316         {
317             get
318             {
319                 int x, y, w, h;
320                 Interop.Evas.evas_object_geometry_get(Handle, out x, out y, out w, out h);
321                 Rect rect = new Rect(x, y, w, h);
322                 return rect;
323             }
324             set
325             {
326                 Interop.Evas.evas_object_geometry_set(Handle, value.X, value.Y, value.Width, value.Height);
327             }
328         }
329
330         /// <summary>
331         /// Sets or gets the general or main color of the given Evas object.
332         /// </summary>
333         public virtual Color Color
334         {
335             get
336             {
337                 int r, g, b, a;
338                 Interop.Evas.evas_object_color_get(RealHandle, out r, out g, out b, out a);
339                 return Color.FromRgba(r, g, b, a);
340             }
341             set
342             {
343                 Interop.Evas.SetPremultipliedColor(RealHandle, value.R, value.G, value.B, value.A);
344             }
345         }
346
347         /// <summary>
348         /// Sets or gets the map enabled state.
349         /// </summary>
350         public bool IsMapEnabled
351         {
352             get
353             {
354                 return Interop.Evas.evas_object_map_enable_get(Handle);
355             }
356             set
357             {
358                 Interop.Evas.evas_object_map_enable_set(Handle, value);
359             }
360         }
361
362         /// <summary>
363         /// Sets or gets current object transformation map.
364         /// </summary>
365         public EvasMap EvasMap
366         {
367             get
368             {
369                 IntPtr evasMap = Interop.Evas.evas_object_map_get(Handle);
370                 return new EvasMap(evasMap);
371             }
372             set
373             {
374                 Interop.Evas.evas_object_map_set(Handle, value.Handle);
375             }
376         }
377
378         /// <summary>
379         /// Sets or gets whether an object is to repeat events.
380         /// </summary>
381         public bool RepeatEvents
382         {
383             get
384             {
385                 return Interop.Evas.evas_object_repeat_events_get(RealHandle);
386             }
387             set
388             {
389                 Interop.Evas.evas_object_repeat_events_set(RealHandle, value);
390             }
391         }
392
393         /// <summary>
394         /// Sets or gets whether events on a smart object's member should get propagated up to its parent.
395         /// </summary>
396         public bool PropagateEvents
397         {
398             get
399             {
400                 return Interop.Evas.evas_object_propagate_events_get(RealHandle);
401             }
402             set
403             {
404                 Interop.Evas.evas_object_propagate_events_set(RealHandle, value);
405             }
406         }
407
408         /// <summary>
409         /// Sets or gets whether an object is set to pass (ignore) events.
410         /// </summary>
411         public bool PassEvents
412         {
413             get
414             {
415                 return Interop.Evas.evas_object_pass_events_get(RealHandle);
416             }
417             set
418             {
419                 Interop.Evas.evas_object_pass_events_set(RealHandle, value);
420             }
421         }
422
423         /// <summary>
424         /// Clips one object to another.
425         /// </summary>
426         /// <param name="clip">The object to clip object by</param>
427         public void SetClip(EvasObject clip)
428         {
429             Interop.Evas.evas_object_clip_set(Handle, clip);
430         }
431
432         /// <summary>
433         /// Sets the hints for an object's alignment.
434         /// </summary>
435         /// <param name="x">The horizontal alignment hint as double value ranging from 0.0 to 1.0,The default alignment hint value is 0.5 </param>
436         /// <param name="y">The vertical alignment hint as double value ranging from 0.0 to 1.0,The default alignment hint value is 0.5 </param>
437         public void SetAlignment(double x, double y)
438         {
439             Interop.Evas.evas_object_size_hint_align_set(Handle, x, y);
440         }
441
442         /// <summary>
443         /// Sets the hints for an object's weight.
444         /// </summary>
445         /// <param name="x">The non-negative double value to use as horizontal weight hint</param>
446         /// <param name="y">The non-negative double value to use as vertical weight hint</param>
447         public void SetWeight(double x, double y)
448         {
449             Interop.Evas.evas_object_size_hint_weight_set(Handle, x, y);
450         }
451
452         /// <summary>
453         /// Sets the text for an object's tooltip.
454         /// </summary>
455         /// <param name="text">The text value to display inside the tooltip</param>
456         public void SetTooltipText(string text)
457         {
458             Interop.Elementary.elm_object_tooltip_text_set(RealHandle, text);
459         }
460
461         /// <summary>
462         /// Unsets an object's tooltip.
463         /// </summary>
464         public void UnsetTooltip()
465         {
466             Interop.Elementary.elm_object_tooltip_unset(RealHandle);
467         }
468
469         /// <summary>
470         /// Makes the current object visible.
471         /// </summary>
472         public void Show()
473         {
474             Interop.Evas.evas_object_show(Handle);
475         }
476
477         /// <summary>
478         /// Makes the current object invisible.
479         /// </summary>
480         public void Hide()
481         {
482             Interop.Evas.evas_object_hide(Handle);
483         }
484
485         /// <summary>
486         /// Changes the size of the current object.
487         /// </summary>
488         /// <param name="w">The new width</param>
489         /// <param name="h">The new height</param>
490         public void Resize(int w, int h)
491         {
492             Interop.Evas.evas_object_resize(Handle, w, h);
493         }
494
495         /// <summary>
496         /// Moves the current object to the given location.
497         /// </summary>
498         /// <param name="x">The X position to move the object to.</param>
499         /// <param name="y">The Y position to move the object to.</param>
500         public void Move(int x, int y)
501         {
502             Interop.Evas.evas_object_move(Handle, x, y);
503         }
504
505         /// <summary>
506         /// Lowers obj to the bottom of its layer.
507         /// </summary>
508         public void Lower()
509         {
510             Interop.Evas.evas_object_lower(Handle);
511         }
512
513         /// <summary>
514         /// Define IntPtr operator
515         /// </summary>
516         /// <param name="obj">Parent object</param>
517         public static implicit operator IntPtr(EvasObject obj)
518         {
519             if (obj == null)
520                 return IntPtr.Zero;
521             return obj.Handle;
522         }
523
524         /// <summary>
525         /// Requests keyname key events be directed to current obj.
526         /// </summary>
527         /// <param name="keyname">The key to request events for</param>
528         /// <param name="exclusive">Set TRUE to request that the obj is the only object receiving the keyname events,otherwise set FALSE</param>
529         /// <returns>If the call succeeded is true,otherwise is false</returns>
530         public bool KeyGrab(string keyname, bool exclusive)
531         {
532             return Interop.Evas.evas_object_key_grab(Handle, keyname, 0, 0, exclusive);
533         }
534
535         /// <summary>
536         /// Removes the grab on keyname key events.
537         /// </summary>
538         /// <param name="keyname">The key the grab is set for</param>
539         public void KeyUngrab(string keyname)
540         {
541             Interop.Evas.evas_object_key_ungrab(Handle, keyname, 0, 0);
542         }
543
544         /// <summary>
545         /// Mark smart object as changed.
546         /// </summary>
547         public void MarkChanged()
548         {
549             Interop.Evas.evas_object_smart_changed(RealHandle);
550         }
551
552         /// <summary>
553         /// The callback of Invalidate Event
554         /// </summary>
555         protected virtual void OnInvalidate()
556         {
557         }
558
559         /// <summary>
560         /// The callback of Instantiated Event
561         /// </summary>
562         protected virtual void OnInstantiated()
563         {
564         }
565         /// <summary>
566         /// The callback of Realized Event
567         /// </summary>
568         protected virtual void OnRealized()
569         {
570         }
571         /// <summary>
572         /// The callback of Unrealize Event
573         /// </summary>
574         protected virtual void OnUnrealize()
575         {
576         }
577         /// <summary>
578         /// Creates a widget handle.
579         /// </summary>
580         /// <param name="parent">Parent EvasObject</param>
581         /// <returns>Handle IntPtr</returns>
582         protected abstract IntPtr CreateHandle(EvasObject parent);
583
584         /// <summary>
585         /// For this object bind Parent object.Init handle and all kinds of EvasObjectEvent.
586         /// </summary>
587         /// <param name="parent">Parent object</param>
588         public void Realize(EvasObject parent)
589         {
590             if (!IsRealized)
591             {
592                 Parent = parent;
593                 Handle = CreateHandle(parent);
594                 Debug.Assert(Handle != IntPtr.Zero);
595
596                 (parent as Window)?.AddChild(this);
597
598                 OnRealized();
599                 _deleted = new EvasObjectEvent(this, EvasObjectCallbackType.Del);
600                 _keydown = new EvasObjectEvent<EvasKeyEventArgs>(this, EvasObjectCallbackType.KeyDown, EvasKeyEventArgs.Create);
601                 _keyup = new EvasObjectEvent<EvasKeyEventArgs>(this, EvasObjectCallbackType.KeyUp, EvasKeyEventArgs.Create);
602                 _moved = new EvasObjectEvent(this, EvasObjectCallbackType.Move);
603                 _resized = new EvasObjectEvent(this, EvasObjectCallbackType.Resize);
604
605                 _deleted.On += (s, e) => MakeInvalidate();
606                 _keydown.On += (s, e) => KeyDown?.Invoke(this, e);
607                 _keyup.On += (s, e) => KeyUp?.Invoke(this, e);
608             }
609         }
610
611         /// <summary>
612         /// Removes current object relationship with others.
613         /// </summary>
614         public void Unrealize()
615         {
616             if (IsRealized)
617             {
618                 if(_renderPostCallback != null)
619                 {
620                     Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(Handle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback);
621                     _renderPostCallback = null;
622                 }
623
624                 OnUnrealize();
625                 IntPtr toBeDeleted = Handle;
626                 Handle = IntPtr.Zero;
627
628                 DisposeEvent();
629
630                 (Parent as Window)?.RemoveChild(this);
631
632                 Interop.Evas.evas_object_del(toBeDeleted);
633                 Parent = null;
634             }
635         }
636
637         private void MakeInvalidate()
638         {
639             Deleted?.Invoke(this, EventArgs.Empty);
640             OnInvalidate();
641             Handle = IntPtr.Zero;
642
643             MakeInvalidateEvent();
644
645             (Parent as Window)?.RemoveChild(this);
646             Parent = null;
647             _deleted = null;
648         }
649
650         private void DisposeEvent()
651         {
652             foreach (var evt in _eventStore)
653             {
654                 evt.Dispose();
655             }
656             _eventStore.Clear();
657         }
658         private void MakeInvalidateEvent()
659         {
660             foreach (var evt in _eventStore)
661             {
662                 evt.MakeInvalidate();
663             }
664             _eventStore.Clear();
665         }
666
667         internal void AddToEventLifeTracker(IInvalidatable item)
668         {
669             _eventStore.Add(item);
670         }
671
672     }
673 }