using System;
using System.Collections.Generic;
using System.ComponentModel;
using Xamarin.Forms.Internals;
using System.Linq;
using ElmSharp;
using ESize = ElmSharp.Size;
using ERect = ElmSharp.Rect;
using EFocusDirection = ElmSharp.FocusDirection;
using Specific = Xamarin.Forms.PlatformConfiguration.TizenSpecific.VisualElement;
using XFocusDirection = Xamarin.Forms.PlatformConfiguration.TizenSpecific.FocusDirection;
namespace Xamarin.Forms.Platform.Tizen
{
///
/// Base class for rendering of a Xamarin element.
///
public abstract class VisualElementRenderer : IVisualElementRenderer, IEffectControlProvider where TElement : VisualElement
{
///
/// Holds registered element changed handlers.
///
readonly List> _elementChangedHandlers = new List>();
///
/// Handler for property changed events.
///
PropertyChangedEventHandler _propertyChangedHandler;
EventHandler> _batchCommittedHandler;
///
/// Flags which control status of renderer.
///
VisualElementRendererFlags _flags = VisualElementRendererFlags.None;
///
/// Holds the native view.
///
EvasObject _view;
Dictionary> _propertyHandlersWithInit = new Dictionary>();
Dictionary _propertyHandlers = new Dictionary();
HashSet _batchedProperties = new HashSet();
bool _movedCallbackEnabled = false;
///
/// Default constructor.
///
protected VisualElementRenderer()
{
RegisterPropertyHandler(VisualElement.IsVisibleProperty, UpdateIsVisible);
RegisterPropertyHandler(VisualElement.OpacityProperty, UpdateOpacity);
RegisterPropertyHandler(VisualElement.IsEnabledProperty, UpdateIsEnabled);
RegisterPropertyHandler(VisualElement.InputTransparentProperty, UpdateInputTransparent);
RegisterPropertyHandler(VisualElement.BackgroundColorProperty, UpdateBackgroundColor);
RegisterPropertyHandler(Specific.StyleProperty, UpdateThemeStyle);
RegisterPropertyHandler(Specific.IsFocusAllowedProperty, UpdateFocusAllowed);
RegisterPropertyHandler(Specific.NextFocusDirectionProperty, UpdateFocusDirection);
RegisterPropertyHandler(Specific.NextFocusUpViewProperty, UpdateFocusUpView);
RegisterPropertyHandler(Specific.NextFocusDownViewProperty, UpdateFocusDownView);
RegisterPropertyHandler(Specific.NextFocusLeftViewProperty, UpdateFocusLeftView);
RegisterPropertyHandler(Specific.NextFocusRightViewProperty, UpdateFocusRightView);
RegisterPropertyHandler(Specific.NextFocusBackViewProperty, UpdateFocusBackView);
RegisterPropertyHandler(Specific.NextFocusForwardViewProperty, UpdateFocusForwardView);
RegisterPropertyHandler(Specific.ToolTipProperty, UpdateToolTip);
RegisterPropertyHandler(VisualElement.AnchorXProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.AnchorYProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.ScaleProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.RotationProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.RotationXProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.RotationYProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.TranslationXProperty, ApplyTransformation);
RegisterPropertyHandler(VisualElement.TranslationYProperty, ApplyTransformation);
}
~VisualElementRenderer()
{
Dispose(false);
}
event EventHandler ElementChanged
{
add
{
_elementChangedHandlers.Add(value);
}
remove
{
_elementChangedHandlers.Remove(value);
}
}
///
/// Gets the Xamarin element associated with this renderer.
///
public TElement Element
{
get;
private set;
}
VisualElement IVisualElementRenderer.Element
{
get
{
return this.Element;
}
}
public EvasObject NativeView
{
get
{
return _view;
}
}
protected bool IsDisposed => _flags.HasFlag(VisualElementRendererFlags.Disposed);
///
/// Releases all resource used by the object.
///
/// Call when you are finished using the
/// . The method
/// leaves the in an unusable state.
/// After calling , you must release all references to the
/// so the garbage collector can reclaim
/// the memory that the was occupying.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
if (null == NativeView)
{
return new SizeRequest(new Size(0, 0));
}
else
{
int availableWidth = Forms.ConvertToScaledPixel(widthConstraint);
int availableHeight = Forms.ConvertToScaledPixel(heightConstraint);
if (availableWidth < 0)
availableWidth = int.MaxValue;
if (availableHeight < 0)
availableHeight = int.MaxValue;
Size measured;
var nativeViewMeasurable = NativeView as Native.IMeasurable;
if (nativeViewMeasurable != null)
{
measured = nativeViewMeasurable.Measure(availableWidth, availableHeight).ToDP();
}
else
{
measured = Measure(availableWidth, availableHeight).ToDP();
}
return new SizeRequest(measured, MinimumSize());
}
}
///
/// Sets the element associated with this renderer.
///
public void SetElement(TElement newElement)
{
if (newElement == null)
{
throw new ArgumentNullException("newElement");
}
TElement oldElement = Element;
if (oldElement != null)
{
throw new InvalidOperationException("oldElement");
}
Element = newElement;
if (_propertyChangedHandler == null)
{
_propertyChangedHandler = new PropertyChangedEventHandler(OnElementPropertyChanged);
}
if (_batchCommittedHandler == null)
{
_batchCommittedHandler = OnBatchCommitted;
}
// send notification
OnElementChanged(new ElementChangedEventArgs(oldElement, newElement));
// store renderer for the new element
Platform.SetRenderer(newElement, this);
// add children
var logicalChildren = (newElement as IElementController).LogicalChildren;
foreach (Element child in logicalChildren)
{
AddChild(child);
}
OnElementReady();
}
public void UpdateNativeGeometry()
{
var updatedGeometry = new Rectangle(ComputeAbsolutePoint(Element), new Size(Element.Width, Element.Height)).ToPixel();
if (NativeView.Geometry != updatedGeometry)
{
NativeView.Geometry = updatedGeometry;
ApplyTransformation();
}
}
void IVisualElementRenderer.SetElement(VisualElement element)
{
TElement tElement = element as TElement;
if (tElement == null)
{
throw new ArgumentException("Element is not of type " + typeof(TElement), "Element");
}
SetElement(tElement);
}
///
/// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform.
///
/// The effect to register.
void IEffectControlProvider.RegisterEffect(Effect effect)
{
RegisterEffect(effect);
}
///
/// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform.
///
/// The effect to register.
protected void RegisterEffect(Effect effect)
{
var platformEffect = effect as PlatformEffect;
if (platformEffect != null)
{
OnRegisterEffect(platformEffect);
}
}
protected virtual void UpdateLayout()
{
if (null != NativeView)
{
UpdateNativeGeometry();
}
}
///
/// Disposes of underlying resources.
///
/// True if the memory release was requested on demand.
protected virtual void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
_flags |= VisualElementRendererFlags.Disposed;
if (disposing)
{
if (Element != null)
{
Element.PropertyChanged -= _propertyChangedHandler;
Element.BatchCommitted -= _batchCommittedHandler;
Element.ChildAdded -= OnChildAdded;
Element.ChildRemoved -= OnChildRemoved;
Element.ChildrenReordered -= OnChildrenReordered;
Element.FocusChangeRequested -= OnFocusChangeRequested;
Element.Layout(new Rectangle(0, 0, -1, -1));
var logicalChildren = (Element as IElementController).LogicalChildren;
foreach (var child in logicalChildren)
{
Platform.GetRenderer(child)?.Dispose();
}
if (Platform.GetRenderer(Element) == this)
{
Platform.SetRenderer(Element, (IVisualElementRenderer)null);
}
Element = default(TElement);
}
if (NativeView != null)
{
NativeView.Deleted -= NativeViewDeleted;
NativeView.Unrealize();
SetNativeView(null);
}
}
}
///
/// Notification that the associated element has changed.
///
/// Event parameters.
protected virtual void OnElementChanged(ElementChangedEventArgs e)
{
if (null != e.OldElement)
{
e.OldElement.PropertyChanged -= _propertyChangedHandler;
e.OldElement.BatchCommitted -= _batchCommittedHandler;
e.OldElement.ChildAdded -= OnChildAdded;
e.OldElement.ChildRemoved -= OnChildRemoved;
e.OldElement.ChildrenReordered -= OnChildrenReordered;
e.OldElement.FocusChangeRequested -= OnFocusChangeRequested;
Element.Layout(new Rectangle(0, 0, -1, -1));
var controller = e.OldElement as IElementController;
if (controller != null && controller.EffectControlProvider == this)
{
controller.EffectControlProvider = null;
}
}
if (null != e.NewElement)
{
e.NewElement.PropertyChanged += _propertyChangedHandler;
e.NewElement.BatchCommitted += _batchCommittedHandler;
e.NewElement.ChildAdded += OnChildAdded;
e.NewElement.ChildRemoved += OnChildRemoved;
e.NewElement.ChildrenReordered += OnChildrenReordered;
e.NewElement.FocusChangeRequested += OnFocusChangeRequested;
UpdateAllProperties(true);
var controller = e.NewElement as IElementController;
if (controller != null)
{
controller.EffectControlProvider = this;
}
}
// TODO: handle the event
}
///
/// Notification that the property of the associated element has changed.
///
/// Object which sent the notification.
/// Event parameters.
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (Element.Batched)
{
if (e.PropertyName == VisualElement.XProperty.PropertyName ||
e.PropertyName == VisualElement.YProperty.PropertyName ||
e.PropertyName == VisualElement.WidthProperty.PropertyName ||
e.PropertyName == VisualElement.HeightProperty.PropertyName)
{
_flags |= VisualElementRendererFlags.NeedsLayout;
}
else if (e.PropertyName == VisualElement.TranslationXProperty.PropertyName ||
e.PropertyName == VisualElement.TranslationYProperty.PropertyName ||
e.PropertyName == VisualElement.RotationProperty.PropertyName ||
e.PropertyName == VisualElement.RotationXProperty.PropertyName ||
e.PropertyName == VisualElement.RotationYProperty.PropertyName ||
e.PropertyName == VisualElement.ScaleProperty.PropertyName ||
e.PropertyName == VisualElement.AnchorXProperty.PropertyName ||
e.PropertyName == VisualElement.AnchorYProperty.PropertyName)
{
_flags |= VisualElementRendererFlags.NeedsTransformation;
}
else
{
_batchedProperties.Add(e.PropertyName);
}
return;
}
Action init;
if (_propertyHandlersWithInit.TryGetValue(e.PropertyName, out init))
{
init(false);
}
else
{
Action handler;
if (_propertyHandlers.TryGetValue(e.PropertyName, out handler))
{
handler();
}
}
}
///
/// Updates the attached event handlers, sets the native control.
///
protected void SetNativeControl(EvasObject control)
{
if (NativeView != null)
{
if (_movedCallbackEnabled)
{
NativeView.Moved -= OnMoved;
}
NativeView.Deleted -= NativeViewDeleted;
}
Widget widget = NativeView as Widget;
if (widget != null)
{
widget.Focused -= OnFocused;
widget.Unfocused -= OnUnfocused;
}
SetNativeView(control);
if (NativeView != null)
{
NativeView.Deleted += NativeViewDeleted;
if (_movedCallbackEnabled)
{
NativeView.Moved += OnMoved;
}
}
widget = NativeView as Widget;
if (widget != null)
{
widget.Focused += OnFocused;
widget.Unfocused += OnUnfocused;
}
}
void NativeViewDeleted(object sender, EventArgs e)
{
Dispose();
}
void OnBatchCommitted(object sender, EventArg e)
{
if (_flags.HasFlag(VisualElementRendererFlags.NeedsLayout))
{
UpdateLayout();
// UpdateLayout already updates transformation, clear NeedsTranformation flag then
_flags &= ~VisualElementRendererFlags.NeedsTransformation;
_flags ^= VisualElementRendererFlags.NeedsLayout;
}
if (_flags.HasFlag(VisualElementRendererFlags.NeedsTransformation))
{
ApplyTransformation();
_flags ^= VisualElementRendererFlags.NeedsTransformation;
}
foreach (string property in _batchedProperties)
{
OnElementPropertyChanged(this, new PropertyChangedEventArgs(property));
}
_batchedProperties.Clear();
}
///
/// Registers a handler which is executed when specified property changes.
///
/// Handled property.
/// Action to be executed when property changes.
protected void RegisterPropertyHandler(BindableProperty property, Action handler)
{
RegisterPropertyHandler(property.PropertyName, handler);
}
///
/// Registers a handler which is executed when specified property changes.
///
/// Name of the handled property.
/// Action to be executed when property changes.
protected void RegisterPropertyHandler(string name, Action handler)
{
_propertyHandlersWithInit.Add(name, handler);
}
///
/// Registers a handler which is executed when specified property changes.
///
/// Handled property.
/// Action to be executed when property changes.
protected void RegisterPropertyHandler(BindableProperty property, Action handler)
{
RegisterPropertyHandler(property.PropertyName, handler);
}
///
/// Registers a handler which is executed when specified property changes.
///
/// Name of the handled property.
/// Action to be executed when property changes.
protected void RegisterPropertyHandler(string name, Action handler)
{
_propertyHandlers.Add(name, handler);
}
///
/// Updates all registered properties.
///
/// If set to true the method is called for an uninitialized object.
protected void UpdateAllProperties(bool initialization)
{
foreach (var action in _propertyHandlersWithInit.Values.Distinct())
{
action(initialization);
}
foreach (var action in _propertyHandlers.Values.Distinct())
{
action();
}
}
///
/// Called when Element has been set and its native counterpart
/// is properly initialized.
///
protected virtual void OnElementReady()
{
}
protected void DoLayout(Native.LayoutEventArgs e)
{
Element.Layout(e.Geometry.ToDP());
}
protected virtual Size MinimumSize()
{
return new ESize(NativeView.MinimumWidth, NativeView.MinimumHeight).ToDP();
}
///
/// Calculates how much space this element should take, given how much room there is.
///
/// a desired dimensions of the element
protected virtual ESize Measure(int availableWidth, int availableHeight)
{
return new ESize(NativeView.MinimumWidth, NativeView.MinimumHeight);
}
protected virtual void UpdateBackgroundColor()
{
if (NativeView is Widget)
{
(NativeView as Widget).BackgroundColor = Element.BackgroundColor.ToNative();
}
else
{
Log.Warn("{0} uses {1} which does not support background color", this, NativeView);
}
}
protected virtual void UpdateOpacity()
{
if (NativeView is Widget)
{
(NativeView as Widget).Opacity = (int)(Element.Opacity * 255.0);
}
else
{
Log.Warn("{0} uses {1} which does not support opacity", this, NativeView);
}
}
static double ComputeAbsoluteX(VisualElement e)
{
return e.X + ((e.RealParent is VisualElement) && !(e.RealParent is ListView) ? Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).NativeView.Geometry.X) : 0.0);
}
static double ComputeAbsoluteY(VisualElement e)
{
return e.Y + ((e.RealParent is VisualElement) && !(e.RealParent is ListView) ? Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).NativeView.Geometry.Y) : 0.0);
}
static Point ComputeAbsolutePoint(VisualElement e)
{
return new Point(ComputeAbsoluteX(e), ComputeAbsoluteY(e));
}
///
/// Handles focus events.
///
void OnFocused(object sender, EventArgs e)
{
if (null != Element)
{
Element.SetValue(VisualElement.IsFocusedPropertyKey, true);
}
}
///
/// Handles unfocus events.
///
void OnUnfocused(object sender, EventArgs e)
{
if (null != Element)
{
Element.SetValue(VisualElement.IsFocusedPropertyKey, false);
}
}
///
/// Sets the native control, updates the control's properties.
///
void SetNativeView(EvasObject control)
{
_view = control;
}
///
/// Adds a new child if it's derived from the VisualElement class. Otherwise this method does nothing.
///
/// Child to be added.
void AddChild(Element child)
{
VisualElement vElement = child as VisualElement;
if (vElement != null)
{
var childRenderer = Platform.GetOrCreateRenderer(vElement);
// if the native view can have children, attach the new child
if (NativeView is Native.IContainable)
{
(NativeView as Native.IContainable).Children.Add(childRenderer.NativeView);
}
}
}
void RemoveChild(VisualElement view)
{
var renderer = Platform.GetRenderer(view);
var containerObject = NativeView as Native.IContainable;
if (containerObject != null)
{
containerObject.Children.Remove(renderer.NativeView);
}
renderer.Dispose();
}
void OnChildAdded(object sender, ElementEventArgs e)
{
var view = e.Element as VisualElement;
if (view != null)
{
AddChild(view);
}
// changing the order makes sense only in case of Layouts
if (Element is Layout)
{
IElementController controller = Element as IElementController;
if (controller.LogicalChildren[controller.LogicalChildren.Count - 1] != view)
{
EnsureChildOrder();
}
}
}
void OnChildRemoved(object sender, ElementEventArgs e)
{
var view = e.Element as VisualElement;
if (view != null)
{
RemoveChild(view);
}
}
void OnChildrenReordered(object sender, EventArgs e)
{
EnsureChildOrder();
Layout layout = Element as Layout;
if (layout != null)
{
layout.InvalidateMeasureNonVirtual(InvalidationTrigger.MeasureChanged);
layout.ForceLayout();
}
}
void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
{
Widget widget = NativeView as Widget;
if (widget == null)
{
Log.Warn("{0} is not a widget, it cannot receive focus", NativeView);
return;
}
widget.SetFocus(e.Focus);
e.Result = true;
}
///
/// On register the effect
///
/// The effect to register.
void OnRegisterEffect(PlatformEffect effect)
{
effect.SetContainer(Element.Parent == null ? null : Platform.GetRenderer(Element.Parent).NativeView);
effect.SetControl(NativeView);
}
void OnMoved(object sender, EventArgs e)
{
ApplyTransformation();
}
void EnsureChildOrder()
{
var logicalChildren = (Element as IElementController).LogicalChildren;
for (var i = logicalChildren.Count - 1; i >= 0; --i)
{
var element = logicalChildren[i] as VisualElement;
if (element != null)
{
Platform.GetRenderer(element).NativeView?.Lower();
}
}
}
void UpdateIsVisible()
{
if (null != NativeView)
{
if (Element.IsVisible)
{
NativeView.Show();
}
else
{
NativeView.Hide();
}
}
}
///
/// Updates the IsEnabled property.
///
void UpdateIsEnabled()
{
var widget = NativeView as Widget;
if (widget != null)
{
widget.IsEnabled = Element.IsEnabled;
}
}
///
/// Updates the InputTransparent property.
///
void UpdateInputTransparent()
{
NativeView.PassEvents = Element.InputTransparent;
}
protected virtual void UpdateThemeStyle()
{
}
void UpdateFocusAllowed(bool initialize)
{
if (!initialize)
{
var widget = NativeView as Widget;
if (widget != null)
{
widget.AllowFocus(Specific.IsFocusAllowed(Element));
}
else
{
Log.Warn("{0} uses {1} which does not support Focus management", this, NativeView);
}
}
}
void UpdateFocusDirection(bool initialize)
{
var direction = Specific.GetNextFocusDirection(Element);
if (!initialize && direction != XFocusDirection.None)
{
var widget = NativeView as Widget;
if (widget != null)
{
widget.FocusNext(ConvertToNativeFocusDirection(direction));
}
else
{
Log.Warn("{0} uses {1} which does not support Focus management", this, NativeView);
}
}
}
void UpdateToolTip()
{
var tooltip = Specific.GetToolTip(Element);
if (tooltip != null)
{
NativeView.SetTooltipText(tooltip);
}
else
{
NativeView.UnsetTooltip();
}
}
void SetNextFocusViewInternal(string direction)
{
var widget = NativeView as Widget;
if (widget != null)
{
EvasObject nativeControl;
switch (direction)
{
case XFocusDirection.Back:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusBackView(Element))?.NativeView;
break;
case XFocusDirection.Forward:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusForwardView(Element))?.NativeView;
break;
case XFocusDirection.Up:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusUpView(Element))?.NativeView;
break;
case XFocusDirection.Down:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusDownView(Element))?.NativeView;
break;
case XFocusDirection.Right:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusRightView(Element))?.NativeView;
break;
case XFocusDirection.Left:
nativeControl = Platform.GetRenderer(Specific.GetNextFocusLeftView(Element))?.NativeView;
break;
default:
nativeControl = null;
break;
}
if (nativeControl != null)
{
widget.SetNextFocusObject(nativeControl, ConvertToNativeFocusDirection(direction));
}
}
else
{
Log.Warn("{0} uses {1} which does not support Focus management", this, NativeView);
}
}
void UpdateFocusUpView(bool initialize)
{
if (!initialize && Specific.GetNextFocusUpView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Up);
}
}
void UpdateFocusDownView(bool initialize)
{
if (!initialize && Specific.GetNextFocusDownView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Down);
}
}
void UpdateFocusLeftView(bool initialize)
{
if (!initialize && Specific.GetNextFocusLeftView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Left);
}
}
void UpdateFocusRightView(bool initialize)
{
if (!initialize && Specific.GetNextFocusRightView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Right);
}
}
void UpdateFocusBackView(bool initialize)
{
if (!initialize && Specific.GetNextFocusBackView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Back);
}
}
void UpdateFocusForwardView(bool initialize)
{
if (!initialize && Specific.GetNextFocusForwardView(Element) != null)
{
SetNextFocusViewInternal(XFocusDirection.Forward);
}
}
void ApplyRotation(EvasMap map, ERect geometry, ref bool changed)
{
var rotationX = Element.RotationX;
var rotationY = Element.RotationY;
var rotationZ = Element.Rotation;
var anchorX = Element.AnchorX;
var anchorY = Element.AnchorY;
// apply rotations
if (rotationX != 0 || rotationY != 0 || rotationZ != 0)
{
map.Rotate3D(rotationX, rotationY, rotationZ, (int)(geometry.X + geometry.Width * anchorX),
(int)(geometry.Y + geometry.Height * anchorY), 0);
changed = true;
}
}
void ApplyScale(EvasMap map, ERect geometry, ref bool changed)
{
var scale = Element.Scale;
// apply scale factor
if (scale != 1.0)
{
map.Zoom(scale, scale,
geometry.X + (int)(geometry.Width * Element.AnchorX),
geometry.Y + (int)(geometry.Height * Element.AnchorY));
changed = true;
}
}
void ApplyTranslation(EvasMap map, ERect geometry, ref bool changed)
{
var shiftX = Forms.ConvertToScaledPixel(Element.TranslationX);
var shiftY = Forms.ConvertToScaledPixel(Element.TranslationY);
// apply translation, i.e. move/shift the object a little
if (shiftX != 0 || shiftY != 0)
{
if (changed)
{
// special care is taken to apply the translation last
Point3D p;
for (int i = 0; i < 4; i++)
{
p = map.GetPointCoordinate(i);
p.X += shiftX;
p.Y += shiftY;
map.SetPointCoordinate(i, p);
}
}
else
{
// in case when we only need translation, then construct the map in a simpler way
geometry.X += shiftX;
geometry.Y += shiftY;
map.PopulatePoints(geometry, 0);
changed = true;
}
}
}
protected virtual void ApplyTransformation()
{
if (null == NativeView)
{
Log.Error("Trying to apply transformation to the non-existent native control");
return;
}
// prepare the EFL effect structure
ERect geometry = NativeView.Geometry;
EvasMap map = new EvasMap(4);
map.PopulatePoints(geometry, 0);
bool changed = false;
ApplyRotation(map, geometry, ref changed);
ApplyScale(map, geometry, ref changed);
ApplyTranslation(map, geometry, ref changed);
NativeView.IsMapEnabled = changed;
if (changed)
{
NativeView.EvasMap = map;
if (!_movedCallbackEnabled)
{
_movedCallbackEnabled = true;
NativeView.Moved += OnMoved;
}
}
else
{
if (_movedCallbackEnabled)
{
_movedCallbackEnabled = false;
NativeView.Moved -= OnMoved;
}
}
}
EFocusDirection ConvertToNativeFocusDirection(string direction) {
if (direction == XFocusDirection.Back) return EFocusDirection.Previous;
if (direction == XFocusDirection.Forward) return EFocusDirection.Next;
if (direction == XFocusDirection.Up) return EFocusDirection.Up;
if (direction == XFocusDirection.Down) return EFocusDirection.Down;
if (direction == XFocusDirection.Right) return EFocusDirection.Right;
if (direction == XFocusDirection.Left) return EFocusDirection.Left;
return EFocusDirection.Next;
}
}
}