/*
* 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
{
public enum TooltipOrientation
{
None,
TopLeft,
Top,
TopRight,
Left,
Center,
Right,
BottomLeft,
Bottom,
BottomRight,
}
public enum AspectControl
{
None = 0, /* Preference on scaling unset */
Neither = 1, /* Same effect as unset preference on scaling */
Horizontal = 2, /* Use all horizontal container space to place an object, using the given aspect */
Vertical = 3, /* Use all vertical container space to place an object, using the given aspect */
Both = 4 /* Use all horizontal @b and vertical container spaces to place an object (never growing it out of those bounds), using the given aspect */
}
///
/// The EcasObject is a base class for other widget class
///
public abstract class EvasObject
{
private IntPtr _realHandle = IntPtr.Zero;
private EvasCanvas _evasCanvas;
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;
Interop.Evas.evas_object_show(_realHandle);
}
}
EvasObjectEvent _deleted;
EvasObjectEvent _keyup;
EvasObjectEvent _keydown;
EvasObjectEvent _moved;
EvasObjectEvent _resized;
EventHandler _renderPost;
Interop.Evas.EvasCallback _renderPostCallback = null;
Interop.Elementary.Elm_Tooltip_Content_Cb _tooltipContentCallback = null;
GetTooltipContentDelegate _tooltipContentDelegate = 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();
_tooltipContentCallback = (d, o, t) =>
{
return _tooltipContentDelegate?.Invoke();
};
}
// 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 == null)
{
Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback);
_renderPostCallback = null;
}
}
}
///
/// Called back when a widget's tooltip is activated and needs content.
///
///
public delegate EvasObject GetTooltipContentDelegate();
///
/// Get widget's status of Realized or not.
///
public bool IsRealized { get { return Handle != IntPtr.Zero; } }
///
/// Gets EvasCanvas
///
public EvasCanvas EvasCanvas
{
get
{
if (_evasCanvas == null)
_evasCanvas = new EvasCanvas(Handle);
return _evasCanvas;
}
}
///
/// 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
{
var result = Interop.Evas.evas_object_repeat_events_get(Handle);
Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_repeat_events_get(RealHandle));
return result;
}
set
{
if (Handle != RealHandle)
{
Interop.Evas.evas_object_repeat_events_set(RealHandle, value);
}
Interop.Evas.evas_object_repeat_events_set(Handle, value);
}
}
///
/// Sets or gets whether events on a smart object's member should get propagated up to its parent.
///
public bool PropagateEvents
{
get
{
var result = Interop.Evas.evas_object_propagate_events_get(Handle);
Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_propagate_events_get(RealHandle));
return result;
}
set
{
if (Handle != RealHandle)
{
Interop.Evas.evas_object_propagate_events_set(RealHandle, value);
}
Interop.Evas.evas_object_propagate_events_set(Handle, value);
}
}
///
/// Sets or gets whether an object is set to pass (ignore) events.
///
public bool PassEvents
{
get
{
var result = Interop.Evas.evas_object_pass_events_get(Handle);
Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_pass_events_get(RealHandle));
return result;
}
set
{
if (Handle != RealHandle)
{
Interop.Evas.evas_object_pass_events_set(RealHandle, value);
}
Interop.Evas.evas_object_pass_events_set(Handle, value);
}
}
///
/// Sets or Gets style for this object tooltip.
///
public string TooltipStyle
{
get
{
return Interop.Elementary.elm_object_tooltip_style_get(RealHandle);
}
set
{
Interop.Elementary.elm_object_tooltip_style_set(RealHandle, value);
}
}
///
/// Sets or gets the orientation of Tooltip.
///
public TooltipOrientation TooltipOrientation
{
get
{
return (TooltipOrientation)Interop.Elementary.elm_object_tooltip_orient_get(RealHandle);
}
set
{
Interop.Elementary.elm_object_tooltip_orient_set(RealHandle, (int)value);
}
}
///
/// Sets or gets size restriction state of an object's tooltip.
///
public bool TooltipWindowMode
{
get
{
return Interop.Elementary.elm_object_tooltip_window_mode_get(RealHandle);
}
set
{
Interop.Elementary.elm_object_tooltip_window_mode_set(RealHandle, value);
}
}
///
/// Sets the content to be shown in the tooltip object.
///
public GetTooltipContentDelegate TooltipContentDelegate
{
get
{
return _tooltipContentDelegate;
}
set
{
_tooltipContentDelegate = value;
if (value != null)
{
Interop.Elementary.elm_object_tooltip_content_cb_set(RealHandle, _tooltipContentCallback, IntPtr.Zero, null);
}
else
{
Interop.Elementary.elm_object_tooltip_content_cb_set(RealHandle, null, IntPtr.Zero, null);
}
}
}
///
/// Gets the movement freeze by 1
/// This gets the movement freeze count by one.
///
public int TooltipMoveFreezeCount
{
get
{
return Interop.Elementary.elm_object_tooltip_move_freeze_get(RealHandle);
}
}
///
/// Sets or gets whether an Evas object is to freeze (discard) events.
///
public bool AllEventsFrozen
{
get
{
var result = Interop.Evas.evas_object_freeze_events_get(Handle);
Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_freeze_events_get(RealHandle));
return result;
}
set
{
if (Handle != RealHandle)
{
Interop.Evas.evas_object_freeze_events_set(RealHandle, value);
}
Interop.Evas.evas_object_freeze_events_set(Handle, value);
}
}
///
/// Sets or gets the layer of its canvas that the given object will be part of.
///
public virtual int Layer
{
get
{
return Interop.Evas.evas_object_layer_get(Handle);
}
set
{
Interop.Evas.evas_object_layer_set(Handle, 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);
}
///
/// This increments the tooltip movement freeze count by one.
/// If the count is more than 0, the tooltip position will be fixed.
///
public void PushTooltipMoveFreeze()
{
Interop.Elementary.elm_object_tooltip_move_freeze_push(RealHandle);
}
///
/// This decrements the tooltip freeze count by one.
///
public void PopTooltipMoveFreeze()
{
Interop.Elementary.elm_object_tooltip_move_freeze_pop(RealHandle);
}
///
/// Force hide tooltip of object.
///
public void HideTooltip()
{
Interop.Elementary.elm_object_tooltip_hide(RealHandle);
}
///
/// Force show tooltip of object.
///
public void ShowTooltip()
{
Interop.Elementary.elm_object_tooltip_show(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);
}
///
/// Call the calculate smart function immediately.
/// This will force immediate calculations needed for renderization of this object.
///
public void Calculate()
{
Interop.Evas.evas_object_smart_calculate(RealHandle);
}
///
/// Sets the hints for an object's aspect ratio.
///
/// The policy or type of aspect ratio to apply to object
/// The integer to use as aspect width ratio term
/// The integer to use as aspect height ratio term
public void SetSizeHintAspect(AspectControl aspect, int w, int h)
{
Interop.Evas.evas_object_size_hint_aspect_set(Handle, (int)aspect, w, h);
}
///
/// Gets the hints for an object's aspect ratio.
///
/// The policy or type of aspect ratio to apply to object
/// The integer to use as aspect width ratio term
/// The integer to use as aspect height ratio term
public void GetSizeHintAspect(out AspectControl aspect, out int w, out int h)
{
int aspectRatio;
Interop.Evas.evas_object_size_hint_aspect_get(Handle, out aspectRatio, out w, out h);
aspect = (AspectControl)aspectRatio;
}
///
/// Stack immediately below anchor.
///
/// The object below which to stack.
public void StackBelow(EvasObject anchor)
{
Interop.Evas.evas_object_stack_below(Handle, anchor);
}
///
/// Stack immediately above anchor.
///
/// The object above which to stack.
public void StackAbove(EvasObject anchor)
{
Interop.Evas.evas_object_stack_above(Handle, anchor);
}
///
/// Raise to the top of its layer.
///
public void RaiseTop()
{
Interop.Evas.evas_object_raise(Handle);
}
///
/// Get the geometry of a line number.
///
/// the line number.
/// x coord of the line.
/// y coord of the line.
/// w coord of the line.
/// h coord of the line.
///
public bool GetTextBlockGeometryByLineNumber(int lineNumber, out int x, out int y, out int w, out int h)
{
return Interop.Evas.evas_object_textblock_line_number_geometry_get(RealHandle, lineNumber, out x, out y, out w, out h);
}
internal IntPtr GetData(string key)
{
return Interop.Evas.evas_object_data_get(RealHandle, key);
}
internal void SetData(string key, IntPtr data)
{
Interop.Evas.evas_object_data_set(RealHandle, key, data);
}
internal IntPtr DeleteData(string key)
{
return Interop.Evas.evas_object_data_del(RealHandle, key);
}
///
/// 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, RealHandle, EvasObjectCallbackType.KeyDown, EvasKeyEventArgs.Create);
_keyup = new EvasObjectEvent(this, RealHandle, 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);
}
}
}