diff options
Diffstat (limited to 'Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs new file mode 100644 index 00000000..8c5c0be0 --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs @@ -0,0 +1,946 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.ComponentModel; +using ElmSharp; +using ELayout = ElmSharp.Layout; +using EColor = ElmSharp.Color; +using ESize = ElmSharp.Size; +using ERect = ElmSharp.Rect; +using ERectangle = ElmSharp.Rectangle; +using EBox = ElmSharp.Box; + +namespace Xamarin.Forms.Platform.Tizen +{ + /// <summary> + /// Base class for rendering of a Xamarin element. + /// </summary> + public abstract class VisualElementRenderer<TElement> : IVisualElementRenderer, IEffectControlProvider where TElement : VisualElement + { + /// <summary> + /// Holds registered element changed handlers. + /// </summary> + readonly List<EventHandler<VisualElementChangedEventArgs>> _elementChangedHandlers = new List<EventHandler<VisualElementChangedEventArgs>>(); + + /// <summary> + /// Handler for property changed events. + /// </summary> + PropertyChangedEventHandler _propertyChangedHandler; + + EventHandler<EventArg<VisualElement>> _batchCommittedHandler; + + /// <summary> + /// Flags which control status of renderer. + /// </summary> + VisualElementRendererFlags _flags = VisualElementRendererFlags.None; + + /// <summary> + /// Holds the native view. + /// </summary> + EvasObject _view; + + Dictionary<string, Action<bool>> _propertyHandlersWithInit = new Dictionary<string, Action<bool>>(); + + Dictionary<string, Action> _propertyHandlers = new Dictionary<string, Action>(); + + HashSet<string> _batchedProperties = new HashSet<string>(); + + ERectangle _opacityLayer; + + internal GestureHandler _gestureHandler; + + /// <summary> + /// Default constructor. + /// </summary> + protected VisualElementRenderer() + { + RegisterPropertyHandler(VisualElement.IsVisibleProperty, UpdateIsVisible); + RegisterPropertyHandler(VisualElement.OpacityProperty, UpdateOpacity); + RegisterPropertyHandler(VisualElement.IsEnabledProperty, UpdateIsEnabled); + RegisterPropertyHandler(VisualElement.InputTransparentProperty, UpdateInputTransparent); + RegisterPropertyHandler(VisualElement.BackgroundColorProperty, UpdateBackgroundColor); + + 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<VisualElementChangedEventArgs> ElementChanged + { + add + { + _elementChangedHandlers.Add(value); + } + remove + { + _elementChangedHandlers.Remove(value); + } + } + + /// <summary> + /// Gets the Xamarin element associated with this renderer. + /// </summary> + public TElement Element + { + get; + private set; + } + + VisualElement IVisualElementRenderer.Element + { + get + { + return this.Element; + } + } + + public EvasObject NativeView + { + get + { + return _view; + } + } + + protected bool IsDisposed => (_flags == VisualElementRendererFlags.Disposed); + + /// <summary> + /// Releases all resource used by the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> object. + /// </summary> + /// <remarks>Call <see cref="Dispose"/> when you are finished using the + /// <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/>. The <see cref="Dispose"/> method + /// leaves the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> in an unusable state. + /// After calling <see cref="Dispose"/>, you must release all references to the + /// <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> so the garbage collector can reclaim + /// the memory that the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> was occupying.</remarks> + 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 = ToNativeDimension(widthConstraint); + int availableHeight = ToNativeDimension(heightConstraint); + ESize measured; + + var nativeViewMeasurable = NativeView as Native.IMeasurable; + if (nativeViewMeasurable != null) + { + measured = nativeViewMeasurable.Measure(availableWidth, availableHeight); + } + else + { + measured = Measure(availableWidth, availableHeight); + } + + return new SizeRequest(new Size(measured.Width, measured.Height), MinimumSize()); + } + } + + /// <summary> + /// Sets the element associated with this renderer. + /// </summary> + 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<TElement>(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 x = ComputeAbsoluteX(Element); + var y = ComputeAbsoluteY(Element); + NativeView.Geometry = new ERect(ToNativeDimension(x), ToNativeDimension(y), ToNativeDimension(Element.Width), ToNativeDimension(Element.Height)); + ApplyTransformation(); + UpdateOpacityLayer(); + } + + 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); + } + + /// <summary> + /// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform. + /// </summary> + /// <param name="effect">The effect to register.</param> + void IEffectControlProvider.RegisterEffect(Effect effect) + { + RegisterEffect(effect); + } + + /// <summary> + /// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform. + /// </summary> + /// <param name="effect">The effect to register.</param> + protected void RegisterEffect(Effect effect) + { + var platformEffect = effect as PlatformEffect; + if (platformEffect != null) + { + OnRegisterEffect(platformEffect); + } + } + + + protected virtual void UpdateLayout() + { + // we're updating the coordinates of native control only if they were modified + // via Xamarin (Settings.IgnoreBatchCommitted is set to false); + // otherwise native control is already in the right place + if (!Settings.IgnoreBatchCommitted && null != NativeView) + { + UpdateNativeGeometry(); + } + + // we're updating just immediate children + var logicalChildren = (Element as IElementController).LogicalChildren; + foreach (var child in logicalChildren) + { + Platform.GetRenderer(child)?.UpdateNativeGeometry(); + } + } + + /// <summary> + /// Disposes of underlying resources. + /// </summary> + /// <param name="disposing">True if the memory release was requested on demand.</param> + protected virtual void Dispose(bool disposing) + { + if ((_flags & VisualElementRendererFlags.Disposed) != 0) + { + 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; + + Settings.StartIgnoringBatchCommitted(); + Element.Layout(new Rectangle(0, 0, -1, -1)); + Settings.StopIgnoringBatchCommitted(); + + 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; + EnsureOpacityLayerIsDestroyed(); + NativeView.Unrealize(); + SetNativeView(null); + } + } + } + + /// <summary> + /// Notification that the associated element has changed. + /// </summary> + /// <param name="e">Event parameters.</param> + protected virtual void OnElementChanged(ElementChangedEventArgs<TElement> 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; + + Settings.StartIgnoringBatchCommitted(); + Element.Layout(new Rectangle(0, 0, -1, -1)); + Settings.StopIgnoringBatchCommitted(); + + 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 + } + + /// <summary> + /// Notification that the property of the associated element has changed. + /// </summary> + /// <param name="sender">Object which sent the notification.</param> + /// <param name="e">Event parameters.</param> + 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<bool> init; + if (_propertyHandlersWithInit.TryGetValue(e.PropertyName, out init)) + { + init(false); + } + else + { + Action handler; + if (_propertyHandlers.TryGetValue(e.PropertyName, out handler)) + { + handler(); + } + } + } + + /// <summary> + /// Updates the attached event handlers, sets the native control. + /// </summary> + protected void SetNativeControl(EvasObject control) + { + if (NativeView != null) + { + NativeView.Moved -= OnMoved; + NativeView.Deleted -= NativeViewDeleted; + EnsureOpacityLayerIsDestroyed(); + } + + Widget widget = NativeView as Widget; + if (widget != null) + { + widget.Focused -= OnFocused; + widget.Unfocused -= OnUnfocused; + } + + SetNativeView(control); + + if (NativeView != null) + { + NativeView.Deleted += NativeViewDeleted; + 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<VisualElement> e) + { + if (_flags.HasFlag(VisualElementRendererFlags.NeedsLayout)) + { + if (!Settings.IgnoreBatchCommitted) + { + 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(); + } + + /// <summary> + /// Registers a handler which is executed when specified property changes. + /// </summary> + /// <param name="property">Handled property.</param> + /// <param name="handler">Action to be executed when property changes.</param> + protected void RegisterPropertyHandler(BindableProperty property, Action<bool> handler) + { + RegisterPropertyHandler(property.PropertyName, handler); + } + + /// <summary> + /// Registers a handler which is executed when specified property changes. + /// </summary> + /// <param name="name">Name of the handled property.</param> + /// <param name="handler">Action to be executed when property changes.</param> + protected void RegisterPropertyHandler(string name, Action<bool> handler) + { + _propertyHandlersWithInit.Add(name, handler); + } + + /// <summary> + /// Registers a handler which is executed when specified property changes. + /// </summary> + /// <param name="property">Handled property.</param> + /// <param name="handler">Action to be executed when property changes.</param> + protected void RegisterPropertyHandler(BindableProperty property, Action handler) + { + RegisterPropertyHandler(property.PropertyName, handler); + } + + /// <summary> + /// Registers a handler which is executed when specified property changes. + /// </summary> + /// <param name="name">Name of the handled property.</param> + /// <param name="handler">Action to be executed when property changes.</param> + protected void RegisterPropertyHandler(string name, Action handler) + { + _propertyHandlers.Add(name, handler); + } + + /// <summary> + /// Updates all registered properties. + /// </summary> + /// <param name="initialization">If set to <c>true</c> the method is called for an uninitialized object.</param> + protected void UpdateAllProperties(bool initialization) + { + foreach (KeyValuePair<string, Action<bool>> kvp in _propertyHandlersWithInit) + { + kvp.Value(initialization); + } + + foreach (KeyValuePair<string, Action> kvp in _propertyHandlers) + { + kvp.Value(); + } + } + + /// <summary> + /// Called when Element has been set and its native counterpart + /// is properly initialized. + /// </summary> + protected virtual void OnElementReady() + { + } + + protected void DoLayout(Native.LayoutEventArgs e) + { + Settings.StartIgnoringBatchCommitted(); + Element.Layout(new Rectangle(Element.X, Element.Y, e.Width, e.Height)); + if (e.HasChanged) + { + UpdateLayout(); + } + Settings.StopIgnoringBatchCommitted(); + } + + protected virtual Size MinimumSize() + { + return new Size(); + } + + /// <summary> + /// Calculates how much space this element should take, given how much room there is. + /// </summary> + /// <returns>a desired dimensions of the element</returns> + 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); + } + } + + /// <summary> + /// Converts provided value to native dimension. + /// </summary> + /// <param name="v">value to be converted.</param> + /// <returns>converted value</returns> + protected static int ToNativeDimension(double v) + { + return (int)Math.Round(v); + } + + static double ComputeAbsoluteX(VisualElement e) + { + return e.X + (e.RealParent is VisualElement ? Platform.GetRenderer(e.RealParent).NativeView.Geometry.X : 0.0); + } + + static double ComputeAbsoluteY(VisualElement e) + { + return e.Y + (e.RealParent is VisualElement ? Platform.GetRenderer(e.RealParent).NativeView.Geometry.Y : 0.0); + } + + /// <summary> + /// Handles focus events. + /// </summary> + void OnFocused(object sender, EventArgs e) + { + if (null != Element) + { + Element.SetValue(VisualElement.IsFocusedPropertyKey, true); + } + } + + /// <summary> + /// Handles unfocus events. + /// </summary> + void OnUnfocused(object sender, EventArgs e) + { + if (null != Element) + { + Element.SetValue(VisualElement.IsFocusedPropertyKey, false); + } + } + + /// <summary> + /// Sets the native control, updates the control's properties. + /// </summary> + void SetNativeView(EvasObject control) + { + _view = control; + } + + /// <summary> + /// Adds a new child if it's derived from the VisualElement class. Otherwise this method does nothing. + /// </summary> + /// <param name="child">Child to be added.</param> + 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<EvasObject>) + { + (NativeView as Native.IContainable<EvasObject>).Children.Add(childRenderer.NativeView); + } + } + } + + void RemoveChild(VisualElement view) + { + var renderer = Platform.GetRenderer(view); + var containerObject = NativeView as Native.IContainable<EvasObject>; + 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.InvalidateMeasureInternal(Internals.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; + } + + /// <summary> + /// On register the effect + /// </summary> + /// <param name="effect">The effect to register.</param> + void OnRegisterEffect(PlatformEffect effect) + { + effect.Container = Element.Parent == null ? null : Platform.GetRenderer(Element.Parent).NativeView; + effect.Control = NativeView; + } + + void OnMoved(object sender, EventArgs e) + { + UpdateOpacityLayer(); + ApplyTransformation(); + _gestureHandler?.UpdateHitBox(); + } + + 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(); + } + } + } + + void UpdateOpacity() + { + if (null != NativeView) + { + if (Element.Opacity < 1.0) + { + EnsureOpacityLayerExists(); + + var alpha = (int)(Element.Opacity * 255.0); + _opacityLayer.Color = new EColor(255, 255, 255, alpha); + } + else + { + EnsureOpacityLayerIsDestroyed(); + } + } + } + + /// <summary> + /// Updates the IsEnabled property. + /// </summary> + void UpdateIsEnabled() + { + Widget widget = NativeView as Widget; + if (widget != null) + { + widget.IsEnabled = Element.IsEnabled; + } + } + + /// <summary> + /// Updates the InputTransparent property. + /// </summary> + void UpdateInputTransparent() + { + NativeView.PassEvents = Element.InputTransparent; + } + + 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 = ToNativeDimension(Element.TranslationX); + var shiftY = ToNativeDimension(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; + } + } + } + + public 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 (_opacityLayer != null) + { + _opacityLayer.IsMapEnabled = true; + _opacityLayer.EvasMap = map; + } + } + _gestureHandler?.UpdateHitBox(); + } + + protected virtual void UpdateOpacityLayer() + { + if (_opacityLayer != null) + { + _opacityLayer.Geometry = NativeView.Geometry; + NativeView.SetClip(_opacityLayer); + } + } + + void EnsureOpacityLayerExists() + { + if (_opacityLayer == null) + { + _opacityLayer = new ERectangle(NativeView); + UpdateOpacityLayer(); + _opacityLayer.Show(); + } + } + + void EnsureOpacityLayerIsDestroyed() + { + if (_opacityLayer != null) + { + NativeView.SetClip(null); + _opacityLayer.Unrealize(); + _opacityLayer = null; + } + } + } + + internal static class Settings + { + static int s_ignoreCount = 0; + + public static bool IgnoreBatchCommitted + { + get + { + return s_ignoreCount != 0; + } + } + + public static void StartIgnoringBatchCommitted() + { + ++s_ignoreCount; + } + + public static void StopIgnoringBatchCommitted() + { + Debug.Assert(s_ignoreCount > 0); + --s_ignoreCount; + } + } +} |