/*
* 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);
}
}
}