<commit_before>﻿using Mapsui.Layers;
using Mapsui.Rendering;
using Mapsui.UI.Forms.Extensions;
using Mapsui.UI.Objects;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Svg.Skia;
using Xamarin.Forms;

namespace Mapsui.UI.Forms
{
    /// <summary>
    /// Class, that uses the API of the original Xamarin.Forms MapView
    /// </summary>
    public class MapView : ContentView, IMapControl, INotifyPropertyChanged, IEnumerable<Pin>
    {
        internal MapControl _mapControl;
        private const string CalloutLayerName = "Callouts";
        private const string PinLayerName = "Pins";
        private const string DrawableLayerName = "Drawables";
        private readonly MemoryLayer _mapCalloutLayer;
        private readonly MemoryLayer _mapPinLayer;
        private readonly MemoryLayer _mapDrawableLayer;
        private readonly StackLayout _mapButtons;
        private readonly SvgButton _mapZoomInButton;
        private readonly SvgButton _mapZoomOutButton;
        private readonly Image _mapSpacingButton1;
        private readonly SvgButton _mapMyLocationButton;
        private readonly Image _mapSpacingButton2;
        private readonly SvgButton _mapNorthingButton;
        private readonly SKPicture _pictMyLocationNoCenter;
        private readonly SKPicture _pictMyLocationCenter;

        readonly ObservableRangeCollection<Pin> _pins = new ObservableRangeCollection<Pin>();
        readonly ObservableRangeCollection<Drawable> _drawable = new ObservableRangeCollection<Drawable>();
        readonly ObservableRangeCollection<Callout> _callouts = new ObservableRangeCollection<Callout>();

        /// <summary>
        /// Initializes a new instance of the <see cref="T:Mapsui.UI.Forms.MapView"/> class.
        /// </summary>
        public MapView()
        {
            MyLocationEnabled = false;
            MyLocationFollow = false;

            IsClippedToBounds = true;

            _mapControl = new MapControl { UseDoubleTap = false };
            MyLocationLayer = new MyLocationLayer(this) { Enabled = true };
            _mapCalloutLayer = new MemoryLayer() { Name = CalloutLayerName, IsMapInfoLayer = true };
            _mapPinLayer = new MemoryLayer() { Name = PinLayerName, IsMapInfoLayer = true };
            _mapDrawableLayer = new MemoryLayer() { Name = DrawableLayerName, IsMapInfoLayer = true };

            // Get defaults from MapControl
            RotationLock = Map.RotationLock;
            ZoomLock = Map.ZoomLock;
            PanLock = Map.PanLock;

            // Add some events to _mapControl
            _mapControl.Viewport.ViewportChanged += HandlerViewportChanged;
            _mapControl.ViewportInitialized += HandlerViewportInitialized;
            _mapControl.Info += HandlerInfo;
            _mapControl.PropertyChanged += HandlerMapControlPropertyChanged;
            _mapControl.SingleTap += HandlerTap;
            _mapControl.DoubleTap += HandlerTap;
            _mapControl.LongTap += HandlerLongTap;
            _mapControl.Hovered += HandlerHovered;
            _mapControl.TouchStarted += HandlerTouchStarted;
            _mapControl.TouchEnded += HandlerTouchEnded;
            _mapControl.TouchEntered += HandlerTouchEntered;
            _mapControl.TouchExited += HandlerTouchExited;
            _mapControl.TouchMove += HandlerTouchMove;
            _mapControl.Swipe += HandlerSwipe;
            _mapControl.Fling += HandlerFling;
            _mapControl.Zoomed += HandlerZoomed;

            _mapControl.TouchMove += (s, e) =>
            {
                Device.BeginInvokeOnMainThread(() => MyLocationFollow = false);
            };

            // Add MapView layers to Map
            AddLayers();

            // Add some events to _mapControl.Map.Layers
            _mapControl.Map.Layers.LayerAdded += HandlerLayerChanged;
            _mapControl.Map.Layers.LayerMoved += HandlerLayerChanged;
            _mapControl.Map.Layers.LayerRemoved += HandlerLayerChanged;

            AbsoluteLayout.SetLayoutBounds(_mapControl, new Rectangle(0, 0, 1, 1));
            AbsoluteLayout.SetLayoutFlags(_mapControl, AbsoluteLayoutFlags.All);

            _pictMyLocationNoCenter = new SKSvg().Load(Utilities.EmbeddedResourceLoader.Load("Images.LocationNoCenter.svg", typeof(MapView)));
            _pictMyLocationCenter = new SKSvg().Load(Utilities.EmbeddedResourceLoader.Load("Images.LocationCenter.svg", typeof(MapView)));

            _mapZoomInButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.ZoomIn.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => { _mapControl.Navigator.ZoomIn(); })
            };

            _mapZoomOutButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.ZoomOut.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => { _mapControl.Navigator.ZoomOut(); }),
            };

            _mapSpacingButton1 = new Image { BackgroundColor = Color.Transparent, WidthRequest = 40, HeightRequest = 8, InputTransparent = true };

            _mapMyLocationButton = new SvgButton(_pictMyLocationNoCenter)
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => MyLocationFollow = true),
            };

            _mapSpacingButton2 = new Image { BackgroundColor = Color.Transparent, WidthRequest = 40, HeightRequest = 8, InputTransparent = true };

            _mapNorthingButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.RotationZero.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => Device.BeginInvokeOnMainThread(() => _mapControl.Navigator.RotateTo(0))),
            };

            _mapButtons = new StackLayout { BackgroundColor = Color.Transparent, Spacing = 0, IsVisible = true, InputTransparent = true, CascadeInputTransparent = false };

            _mapButtons.Children.Add(_mapZoomInButton);
            _mapButtons.Children.Add(_mapZoomOutButton);
            _mapButtons.Children.Add(_mapSpacingButton1);
            _mapButtons.Children.Add(_mapMyLocationButton);
            _mapButtons.Children.Add(_mapSpacingButton2);
            _mapButtons.Children.Add(_mapNorthingButton);

            AbsoluteLayout.SetLayoutBounds(_mapButtons, new Rectangle(0.95, 0.03, 40, 176));
            AbsoluteLayout.SetLayoutFlags(_mapButtons, AbsoluteLayoutFlags.PositionProportional);

            Content = new AbsoluteLayout
            {
                Children = {<commit_msg>MapView: adjust button layout on iOS (#1059)<commit_after>﻿using Mapsui.Layers;
using Mapsui.Rendering;
using Mapsui.UI.Forms.Extensions;
using Mapsui.UI.Objects;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Svg.Skia;
using Xamarin.Forms;

namespace Mapsui.UI.Forms
{
    /// <summary>
    /// Class, that uses the API of the original Xamarin.Forms MapView
    /// </summary>
    public class MapView : ContentView, IMapControl, INotifyPropertyChanged, IEnumerable<Pin>
    {
        internal MapControl _mapControl;
        private const string CalloutLayerName = "Callouts";
        private const string PinLayerName = "Pins";
        private const string DrawableLayerName = "Drawables";
        private readonly MemoryLayer _mapCalloutLayer;
        private readonly MemoryLayer _mapPinLayer;
        private readonly MemoryLayer _mapDrawableLayer;
        private readonly StackLayout _mapButtons;
        private readonly SvgButton _mapZoomInButton;
        private readonly SvgButton _mapZoomOutButton;
        private readonly Image _mapSpacingButton1;
        private readonly SvgButton _mapMyLocationButton;
        private readonly Image _mapSpacingButton2;
        private readonly SvgButton _mapNorthingButton;
        private readonly SKPicture _pictMyLocationNoCenter;
        private readonly SKPicture _pictMyLocationCenter;

        readonly ObservableRangeCollection<Pin> _pins = new ObservableRangeCollection<Pin>();
        readonly ObservableRangeCollection<Drawable> _drawable = new ObservableRangeCollection<Drawable>();
        readonly ObservableRangeCollection<Callout> _callouts = new ObservableRangeCollection<Callout>();

        /// <summary>
        /// Initializes a new instance of the <see cref="T:Mapsui.UI.Forms.MapView"/> class.
        /// </summary>
        public MapView()
        {
            MyLocationEnabled = false;
            MyLocationFollow = false;

            IsClippedToBounds = true;

            _mapControl = new MapControl { UseDoubleTap = false };
            MyLocationLayer = new MyLocationLayer(this) { Enabled = true };
            _mapCalloutLayer = new MemoryLayer() { Name = CalloutLayerName, IsMapInfoLayer = true };
            _mapPinLayer = new MemoryLayer() { Name = PinLayerName, IsMapInfoLayer = true };
            _mapDrawableLayer = new MemoryLayer() { Name = DrawableLayerName, IsMapInfoLayer = true };

            // Get defaults from MapControl
            RotationLock = Map.RotationLock;
            ZoomLock = Map.ZoomLock;
            PanLock = Map.PanLock;

            // Add some events to _mapControl
            _mapControl.Viewport.ViewportChanged += HandlerViewportChanged;
            _mapControl.ViewportInitialized += HandlerViewportInitialized;
            _mapControl.Info += HandlerInfo;
            _mapControl.PropertyChanged += HandlerMapControlPropertyChanged;
            _mapControl.SingleTap += HandlerTap;
            _mapControl.DoubleTap += HandlerTap;
            _mapControl.LongTap += HandlerLongTap;
            _mapControl.Hovered += HandlerHovered;
            _mapControl.TouchStarted += HandlerTouchStarted;
            _mapControl.TouchEnded += HandlerTouchEnded;
            _mapControl.TouchEntered += HandlerTouchEntered;
            _mapControl.TouchExited += HandlerTouchExited;
            _mapControl.TouchMove += HandlerTouchMove;
            _mapControl.Swipe += HandlerSwipe;
            _mapControl.Fling += HandlerFling;
            _mapControl.Zoomed += HandlerZoomed;

            _mapControl.TouchMove += (s, e) =>
            {
                Device.BeginInvokeOnMainThread(() => MyLocationFollow = false);
            };

            // Add MapView layers to Map
            AddLayers();

            // Add some events to _mapControl.Map.Layers
            _mapControl.Map.Layers.LayerAdded += HandlerLayerChanged;
            _mapControl.Map.Layers.LayerMoved += HandlerLayerChanged;
            _mapControl.Map.Layers.LayerRemoved += HandlerLayerChanged;

            AbsoluteLayout.SetLayoutBounds(_mapControl, new Rectangle(0, 0, 1, 1));
            AbsoluteLayout.SetLayoutFlags(_mapControl, AbsoluteLayoutFlags.All);

            _pictMyLocationNoCenter = new SKSvg().Load(Utilities.EmbeddedResourceLoader.Load("Images.LocationNoCenter.svg", typeof(MapView)));
            _pictMyLocationCenter = new SKSvg().Load(Utilities.EmbeddedResourceLoader.Load("Images.LocationCenter.svg", typeof(MapView)));

            _mapZoomInButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.ZoomIn.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => { _mapControl.Navigator.ZoomIn(); })
            };

            _mapZoomOutButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.ZoomOut.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => { _mapControl.Navigator.ZoomOut(); }),
            };

            _mapSpacingButton1 = new Image { BackgroundColor = Color.Transparent, WidthRequest = 40, HeightRequest = 8, InputTransparent = true };

            _mapMyLocationButton = new SvgButton(_pictMyLocationNoCenter)
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => MyLocationFollow = true),
            };

            _mapSpacingButton2 = new Image { BackgroundColor = Color.Transparent, WidthRequest = 40, HeightRequest = 8, InputTransparent = true };

            _mapNorthingButton = new SvgButton(Utilities.EmbeddedResourceLoader.Load("Images.RotationZero.svg", typeof(MapView)))
            {
                BackgroundColor = Color.Transparent,
                WidthRequest = 40,
                HeightRequest = 40,
                Command = new Command(obj => Device.BeginInvokeOnMainThread(() => _mapControl.Navigator.RotateTo(0))),
            };

            _mapButtons = new StackLayout { BackgroundColor = Color.Transparent, Spacing = 0, IsVisible = true, InputTransparent = true, CascadeInputTransparent = false };

            _mapButtons.Children.Add(_mapZoomInButton);
            _mapButtons.Children.Add(_mapZoomOutButton);
            _mapButtons.Children.Add(_mapSpacingButton1);
            _mapButtons.Children.Add(_mapMyLocationButton);
            _mapButtons.Children.Add(_mapSpacingButton2);
            _mapButtons.Children.Add(_mapNorthingButton);

            if (Device.RuntimePlatform == Device.iOS)
                // the buttons are placed a bit lower on iOS to avoid overlap with the transparent status bar
                AbsoluteLayout.SetLayoutBounds(_mapButtons, new Rectangle(0.95, 0.07, 40, 176));
            else
                AbsoluteLayout.SetLayoutBounds(_mapButtons, new Rectangle(0.95, 0.03, 40, 176));

            AbsoluteLayout.SetLayoutFlags(_mapButtons, AbsoluteLayoutFlags.PositionProportional);

            Content = new AbsoluteLayout
            {
                Children = {
{'fraction_non_alphanumeric': 0.08220304151253596, 'fraction_numerical': 0.007192766132346897, 'mean_word_length': 2.578186274509804, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3484486', 'n_tokens_mistral': 3879, 'n_tokens_neox': 3639, 'n_words': 789}