/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * 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.Collections.Generic; using System.Diagnostics; namespace ElmSharp { /// /// The EcasObject is a base class for other widget class /// public abstract class EvasObject { private IntPtr _realHandle = IntPtr.Zero; private event EventHandler _backButtonPressed; private event EventHandler _moreButtonPressed; private Interop.Eext.EextEventCallback _backButtonHandler; private Interop.Eext.EextEventCallback _moreButtonHandler; public IntPtr Handle { get; protected set; } public EvasObject Parent { get; private set; } public IntPtr RealHandle { get { return _realHandle == IntPtr.Zero ? Handle : _realHandle; } protected set { _realHandle = value; } } EvasObjectEvent _deleted; EvasObjectEvent _keyup; EvasObjectEvent _keydown; EvasObjectEvent _moved; EvasObjectEvent _resized; EventHandler _renderPost; Interop.Evas.EvasCallback _renderPostCallback = null; readonly HashSet _eventStore = new HashSet(); /// /// Creates and initializes a new instance of the EvasObject class with parent EvasObject class parameter. /// /// Parent EvasObject class protected EvasObject(EvasObject parent) : this() { Debug.Assert(parent == null || parent.IsRealized); Realize(parent); } /// /// Creates and initializes a new instance of the EvasObject class. /// protected EvasObject() { _backButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _backButtonPressed?.Invoke(this, EventArgs.Empty); }); _moreButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _moreButtonPressed?.Invoke(this, EventArgs.Empty); }); OnInstantiated(); } // C# Finalizer was called on GC thread // So, We can't access to EFL object // And When Finalizer was called, Field can be already released. //~EvasObject() //{ // Unrealize(); //} /// /// Deleted will be triggered when widght is deleted /// public event EventHandler Deleted; /// /// KeyUp will be triggered when key is loose /// public event EventHandler KeyUp; /// /// KeyDown will be triggered when key is preesd down /// public event EventHandler KeyDown; /// /// BackButtonPressed will be triggered when Back button is pressed /// public event EventHandler BackButtonPressed { add { if (_backButtonPressed == null) { Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler, IntPtr.Zero); } _backButtonPressed += value; } remove { _backButtonPressed -= value; if (_backButtonPressed == null) { Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler); } } } /// /// MoreButtonPressed will be triggered when More button is pressed /// public event EventHandler MoreButtonPressed { add { if (_moreButtonPressed == null) { Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler, IntPtr.Zero); } _moreButtonPressed += value; } remove { _moreButtonPressed -= value; if (_moreButtonPressed == null) { Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler); } } } /// /// Moved will be triggered when widght is moved /// public event EventHandler Moved { add { _moved.On += value; } remove { _moved.On -= value; } } /// /// Current widget's size Resized Event Handler /// public event EventHandler Resized { add { _resized.On += value; } remove { _resized.On -= value; } } /// /// Current widget RenderPost Event Handler /// public event EventHandler RenderPost { add { _renderPost += value; if (_renderPostCallback == null) { _renderPostCallback = new Interop.Evas.EvasCallback((o, e, d) => _renderPost?.Invoke(this, EventArgs.Empty)); Interop.Evas.evas_event_callback_add(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback, IntPtr.Zero); } } remove { _renderPost -= value; if (_renderPost?.GetInvocationList().Length == 0) { Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback); _renderPostCallback = null; } } } /// /// Get widget's status of Realized or not. /// public bool IsRealized { get { return Handle != IntPtr.Zero; } } /// /// Gets the current class's Name. /// public string ClassName { get { return Interop.Eo.eo_class_name_get(Interop.Eo.eo_class_get(RealHandle)); } } /// /// Sets or gets the horizontal pointer hints for an object's weight. /// public double WeightX { get { return Interop.Evas.GetWeightX(Handle); } set { Interop.Evas.SetWeightX(Handle, value); } } /// /// Sets or gets the vertical pointer hints for an object's weight. /// public double WeightY { get { return Interop.Evas.GetWeightY(Handle); } set { Interop.Evas.SetWeightY(Handle, value); } } /// /// Sets or gets the horizontal alignment hint of an object's alignment. /// public virtual double AlignmentX { get { return Interop.Evas.GetAlignX(Handle); } set { Interop.Evas.SetAlignX(Handle, value); } } /// /// Sets or gets the vertical alignment hint of an object's alignment. /// public virtual double AlignmentY { get { return Interop.Evas.GetAlignY(Handle); } set { Interop.Evas.SetAlignY(Handle, value); } } /// /// Sets or gets the Width hints for an object's minimum size. /// public int MinimumWidth { get { int w, h; Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h); return w; } set { int h = MinimumHeight; Interop.Evas.evas_object_size_hint_min_set(RealHandle, value, h); } } /// /// Sets or gets the Height hints for an object's minimum size. /// public int MinimumHeight { get { int w, h; Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h); return h; } set { int w = MinimumWidth; Interop.Evas.evas_object_size_hint_min_set(RealHandle, w, value); } } /// /// Gets the visible state of the given Evas object. /// public bool IsVisible { get { return Interop.Evas.evas_object_visible_get(Handle); } } /// /// Sets or gets the position and (rectangular) size of the given Evas object. /// public Rect Geometry { get { int x, y, w, h; Interop.Evas.evas_object_geometry_get(Handle, out x, out y, out w, out h); Rect rect = new Rect(x, y, w, h); return rect; } set { Interop.Evas.evas_object_geometry_set(Handle, value.X, value.Y, value.Width, value.Height); } } /// /// Sets or gets the general or main color of the given Evas object. /// public virtual Color Color { get { int r, g, b, a; Interop.Evas.evas_object_color_get(RealHandle, out r, out g, out b, out a); return Color.FromRgba(r, g, b, a); } set { Interop.Evas.SetPremultipliedColor(RealHandle, value.R, value.G, value.B, value.A); } } /// /// Sets or gets the map enabled state. /// public bool IsMapEnabled { get { return Interop.Evas.evas_object_map_enable_get(Handle); } set { Interop.Evas.evas_object_map_enable_set(Handle, value); } } /// /// Sets or gets current object transformation map. /// public EvasMap EvasMap { get { IntPtr evasMap = Interop.Evas.evas_object_map_get(Handle); return new EvasMap(evasMap); } set { Interop.Evas.evas_object_map_set(Handle, value.Handle); } } /// /// Sets or gets whether an object is to repeat events. /// public bool RepeatEvents { get { return Interop.Evas.evas_object_repeat_events_get(RealHandle); } set { Interop.Evas.evas_object_repeat_events_set(RealHandle, value); } } /// /// Sets or gets whether events on a smart object's member should get propagated up to its parent. /// public bool PropagateEvents { get { return Interop.Evas.evas_object_propagate_events_get(RealHandle); } set { Interop.Evas.evas_object_propagate_events_set(RealHandle, value); } } /// /// Sets or gets whether an object is set to pass (ignore) events. /// public bool PassEvents { get { return Interop.Evas.evas_object_pass_events_get(RealHandle); } set { Interop.Evas.evas_object_pass_events_set(RealHandle, value); } } /// /// Clips one object to another. /// /// The object to clip object by public void SetClip(EvasObject clip) { Interop.Evas.evas_object_clip_set(Handle, clip); } /// /// Sets the hints for an object's alignment. /// /// The horizontal alignment hint as double value ranging from 0.0 to 1.0,The default alignment hint value is 0.5 /// The vertical alignment hint as double value ranging from 0.0 to 1.0,The default alignment hint value is 0.5 public void SetAlignment(double x, double y) { Interop.Evas.evas_object_size_hint_align_set(Handle, x, y); } /// /// Sets the hints for an object's weight. /// /// The non-negative double value to use as horizontal weight hint /// The non-negative double value to use as vertical weight hint public void SetWeight(double x, double y) { Interop.Evas.evas_object_size_hint_weight_set(Handle, x, y); } /// /// Sets the text for an object's tooltip. /// /// The text value to display inside the tooltip public void SetTooltipText(string text) { Interop.Elementary.elm_object_tooltip_text_set(RealHandle, text); } /// /// Unsets an object's tooltip. /// public void UnsetTooltip() { Interop.Elementary.elm_object_tooltip_unset(RealHandle); } /// /// Makes the current object visible. /// public void Show() { Interop.Evas.evas_object_show(Handle); } /// /// Makes the current object invisible. /// public void Hide() { Interop.Evas.evas_object_hide(Handle); } /// /// Changes the size of the current object. /// /// The new width /// The new height public void Resize(int w, int h) { Interop.Evas.evas_object_resize(Handle, w, h); } /// /// Moves the current object to the given location. /// /// The X position to move the object to. /// The Y position to move the object to. public void Move(int x, int y) { Interop.Evas.evas_object_move(Handle, x, y); } /// /// Lowers obj to the bottom of its layer. /// public void Lower() { Interop.Evas.evas_object_lower(Handle); } /// /// Define IntPtr operator /// /// Parent object public static implicit operator IntPtr(EvasObject obj) { if (obj == null) return IntPtr.Zero; return obj.Handle; } /// /// Requests keyname key events be directed to current obj. /// /// The key to request events for /// Set TRUE to request that the obj is the only object receiving the keyname events,otherwise set FALSE /// If the call succeeded is true,otherwise is false public bool KeyGrab(string keyname, bool exclusive) { return Interop.Evas.evas_object_key_grab(Handle, keyname, 0, 0, exclusive); } /// /// Removes the grab on keyname key events. /// /// The key the grab is set for public void KeyUngrab(string keyname) { Interop.Evas.evas_object_key_ungrab(Handle, keyname, 0, 0); } /// /// Mark smart object as changed. /// public void MarkChanged() { Interop.Evas.evas_object_smart_changed(RealHandle); } /// /// The callback of Invalidate Event /// protected virtual void OnInvalidate() { } /// /// The callback of Instantiated Event /// protected virtual void OnInstantiated() { } /// /// The callback of Realized Event /// protected virtual void OnRealized() { } /// /// The callback of Unrealize Event /// protected virtual void OnUnrealize() { } /// /// Creates a widget handle. /// /// Parent EvasObject /// Handle IntPtr protected abstract IntPtr CreateHandle(EvasObject parent); /// /// For this object bind Parent object.Init handle and all kinds of EvasObjectEvent. /// /// Parent object public void Realize(EvasObject parent) { if (!IsRealized) { Parent = parent; Handle = CreateHandle(parent); Debug.Assert(Handle != IntPtr.Zero); (parent as Window)?.AddChild(this); OnRealized(); _deleted = new EvasObjectEvent(this, EvasObjectCallbackType.Del); _keydown = new EvasObjectEvent(this, EvasObjectCallbackType.KeyDown, EvasKeyEventArgs.Create); _keyup = new EvasObjectEvent(this, EvasObjectCallbackType.KeyUp, EvasKeyEventArgs.Create); _moved = new EvasObjectEvent(this, EvasObjectCallbackType.Move); _resized = new EvasObjectEvent(this, EvasObjectCallbackType.Resize); _deleted.On += (s, e) => MakeInvalidate(); _keydown.On += (s, e) => KeyDown?.Invoke(this, e); _keyup.On += (s, e) => KeyUp?.Invoke(this, e); } } /// /// Removes current object relationship with others. /// public void Unrealize() { if (IsRealized) { if(_renderPostCallback != null) { Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(Handle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback); _renderPostCallback = null; } OnUnrealize(); IntPtr toBeDeleted = Handle; Handle = IntPtr.Zero; DisposeEvent(); (Parent as Window)?.RemoveChild(this); Interop.Evas.evas_object_del(toBeDeleted); Parent = null; } } private void MakeInvalidate() { Deleted?.Invoke(this, EventArgs.Empty); OnInvalidate(); Handle = IntPtr.Zero; MakeInvalidateEvent(); (Parent as Window)?.RemoveChild(this); Parent = null; _deleted = null; } private void DisposeEvent() { foreach (var evt in _eventStore) { evt.Dispose(); } _eventStore.Clear(); } private void MakeInvalidateEvent() { foreach (var evt in _eventStore) { evt.MakeInvalidate(); } _eventStore.Clear(); } internal void AddToEventLifeTracker(IInvalidatable item) { _eventStore.Add(item); } } }