using System; using System.Collections.Generic; using System.ComponentModel; using Ooui.Forms.Extensions; using Xamarin.Forms; namespace Ooui.Forms { [Flags] public enum VisualElementRendererFlags { Disposed = 1 << 0, AutoTrack = 1 << 1, AutoPackage = 1 << 2 } public class VisualElementRenderer : Ooui.Element, IVisualElementRenderer where TElement : VisualElement { bool disposedValue = false; // To detect redundant calls readonly Color _defaultColor = Color.Clear; readonly PropertyChangedEventHandler _propertyChangedHandler; public TElement Element { get; private set; } VisualElement IVisualElementRenderer.Element => Element; public Element NativeView => this; event EventHandler IVisualElementRenderer.ElementChanged { add { _elementChangedHandlers.Add (value); } remove { _elementChangedHandlers.Remove (value); } } readonly List> _elementChangedHandlers = new List> (); VisualElementRendererFlags _flags = VisualElementRendererFlags.AutoPackage | VisualElementRendererFlags.AutoTrack; VisualElementPackager _packager; VisualElementTracker _tracker; protected bool AutoPackage { get { return (_flags & VisualElementRendererFlags.AutoPackage) != 0; } set { if (value) _flags |= VisualElementRendererFlags.AutoPackage; else _flags &= ~VisualElementRendererFlags.AutoPackage; } } protected bool AutoTrack { get { return (_flags & VisualElementRendererFlags.AutoTrack) != 0; } set { if (value) _flags |= VisualElementRendererFlags.AutoTrack; else _flags &= ~VisualElementRendererFlags.AutoTrack; } } public VisualElementRenderer () : base ("div") { _propertyChangedHandler = OnElementPropertyChanged; } protected virtual void OnElementChanged (ElementChangedEventArgs e) { var args = new VisualElementChangedEventArgs (e.OldElement, e.NewElement); for (int i = 0; i < _elementChangedHandlers.Count; i++) { _elementChangedHandlers[i] (this, args); } var changed = ElementChanged; if (changed != null) changed (this, e); } public event EventHandler> ElementChanged; void IVisualElementRenderer.SetElement (VisualElement element) { SetElement ((TElement)element); } public void SetElement (TElement element) { var oldElement = Element; Element = element; if (oldElement != null) oldElement.PropertyChanged -= _propertyChangedHandler; if (element != null) { if (element.BackgroundColor != Xamarin.Forms.Color.Default || (oldElement != null && element.BackgroundColor != oldElement.BackgroundColor)) SetBackgroundColor (element.BackgroundColor); if (_tracker == null) { _tracker = new VisualElementTracker (this); _tracker.NativeControlUpdated += (sender, e) => UpdateNativeWidget (); } if (AutoPackage && _packager == null) { _packager = new VisualElementPackager (this); _packager.Load (); } //if (AutoTrack && _events == null) { // _events = new EventTracker (this); // _events.LoadEvents (this); //} element.PropertyChanged += _propertyChangedHandler; } OnElementChanged (new ElementChangedEventArgs (oldElement, element)); if (element != null) SendVisualElementInitialized (element, this); if (Element != null && !string.IsNullOrEmpty (Element.AutomationId)) SetAutomationId (Element.AutomationId); } public void SetElementSize (Size size) { Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion (Element, new Rectangle (Element.X, Element.Y, size.Width, size.Height)); } protected virtual void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e) { if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) { SetBackgroundColor (Element.BackgroundColor); } else if (e.PropertyName == Layout.IsClippedToBoundsProperty.PropertyName) { //UpdateClipToBounds (); } } protected virtual void OnRegisterEffect (PlatformEffect effect) { //effect.Container = this; } protected virtual void SetAutomationId (string id) { } protected virtual void SetBackgroundColor (Xamarin.Forms.Color color) { if (color == Xamarin.Forms.Color.Default) Style.BackgroundColor = _defaultColor; else Style.BackgroundColor = color.ToOouiColor (); } protected virtual void UpdateNativeWidget () { } protected virtual void SendVisualElementInitialized (VisualElement element, Element nativeView) { element.SendViewInitialized (nativeView); } protected virtual void Dispose (bool disposing) { if (!disposedValue) { if (disposing) { } disposedValue = true; } } public void Dispose () { Dispose (true); } } }