<|start_filename|>FluentEditorShared/DependencyContainer/DependencyContainer.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;

namespace FluentEditorShared.DependencyContainer
{
    // It is common for a dependency container to use Type as its key. In this case we want to be able to have multiple dependencies of the same type so an explicit Id is needed.
    // This implementation also does not allow for removal of dependencies once added. That is not a needed feature at this time and would require that users of such a container subscribe to events and handle cases of their dependencies being removed at runtime.
    public class DependencyContainer : IDependencyContainer
    {
        private object _lock = new object();
        private readonly Dictionary<string, object> _dependencies = new Dictionary<string, object>();

        public void AddDependency<T>(string id, T dependency) where T : class
        {
            lock (_lock)
            {
                if (_dependencies.ContainsKey(id))
                {
                    throw new Exception(string.Format("A dependency with id {0} already exists", id));
                }
                _dependencies.Add(id, dependency);
            }
        }

        public T GetDependency<T>(string id) where T : class
        {
            lock (_lock)
            {
                if (!_dependencies.ContainsKey(id))
                {
                    return null;
                }
                var d = _dependencies[id];
                if (d is T retVal)
                {
                    return retVal;
                }
                else
                {
                    throw new Exception(string.Format("A dependency with id {0} exists but is of type {1} not {2}", id, d.GetType().ToString(), typeof(T).ToString()));
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Converters.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Markup;

namespace FluentEditorShared
{
    public class ColorToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if(value is Color c)
            {
                return c.ToString();
            }
            else
            {
                return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            try
            {
                var boxedColor = XamlBindingHelper.ConvertValue(typeof(Color), value);
                if(boxedColor is Color c)
                {
                    return c;
                }
                else
                {
                    return Colors.White;
                }
            }
            catch
            {
                return Colors.White;
            }
        }
    }

    public class NullableColorToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value is Nullable<Color>)
            {
                var c = (Color?)value;
                if(c.HasValue)
                {
                    return c.Value.ToString();
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            try
            {
                var boxedColor = XamlBindingHelper.ConvertValue(typeof(Color), value);
                if (boxedColor is Color c)
                {
                    return new Color?(c);
                }
                else
                {
                    return new Color?(Colors.White);
                }
            }
            catch
            {
                return new Color?(Colors.White);
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Utils/ClippedPixelBlob.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public class ClippedPixelBlob : IPixelBlob
    {
        #region Helper for loading from a stream

        public static async Task<ClippedPixelBlob> LoadPixelsFromStream(IRandomAccessStream source)
        {
            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(source);

            if (decoder.BitmapPixelFormat != BitmapPixelFormat.Rgba8 && decoder.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
            {
                throw new Exception("Unsupported pixel format");
            }

            var pixelData = await decoder.GetPixelDataAsync();
            var pixelBytes = pixelData.DetachPixelData();

            return new ClippedPixelBlob(pixelBytes, decoder.BitmapPixelFormat, decoder.OrientedPixelWidth, decoder.OrientedPixelHeight);
        }

        #endregion

        // The pixelBytes array is never changed by this class
        public ClippedPixelBlob(byte[] pixelBytes, BitmapPixelFormat pixelFormat, uint width, uint height)
        {
            if (pixelFormat != BitmapPixelFormat.Rgba8 && pixelFormat != BitmapPixelFormat.Bgra8)
            {
                throw new Exception("Unsupported pixel format");
            }
            if ((long)width * (long)height * 4L >= (long)int.MaxValue)
            {
                throw new Exception("Image too large");
            }
            uint expectedSize = (width * height) * 4;
            if (pixelBytes.Length != expectedSize)
            {
                throw new Exception("Pixel array length does not match dimensions");
            }
            _pixelBytes = pixelBytes;
            _pixelFormat = pixelFormat;
            _imageWidth = width;
            _imageHeight = height;
            _imagePixels = _imageWidth * _imageHeight;

            SetClip(0, 0, _imageWidth, _imageHeight);
        }

        public ClippedPixelBlob(ClippedPixelBlob source)
        {
            _imageWidth = source._imageWidth;
            _imageHeight = source._imageHeight;
            _imagePixels = source._imagePixels;
            _clipLeft = source._clipLeft;
            _clipTop = source._clipTop;
            _clipWidth = source._clipWidth;
            _clipHeight = source._clipHeight;
            _clipPixels = source._clipPixels;
            _pixelBytes = source._pixelBytes;
            _pixelFormat = source._pixelFormat;
        }

        private readonly uint _imageWidth = 0;
        public uint ImageWidth
        {
            get { return _imageWidth; }
        }

        private readonly uint _imageHeight = 0;
        public uint ImageHeight
        {
            get { return _imageHeight; }
        }

        private readonly uint _imagePixels = 0;
        public uint ImagePixels
        {
            get { return _imagePixels; }
        }

        private uint _clipLeft = 0;
        private uint _clipTop = 0;
        private uint _clipWidth = 0;
        private uint _clipHeight = 0;
        private uint _clipPixels = 0;

        public void SetClip(uint left, uint top, uint width, uint height)
        {
            if (left > _imageWidth)
            {
                left = _imageWidth;
            }
            if (left + width > _imageWidth)
            {
                width = _imageWidth - left;
            }

            if (top > _imageHeight)
            {
                top = _imageHeight;
            }
            if (top + height > _imageHeight)
            {
                height = _imageHeight - top;
            }

            _clipLeft = left;
            _clipTop = top;
            _clipWidth = width;
            _clipHeight = height;

            _clipPixels = _clipWidth * _clipHeight;
        }

        private readonly byte[] _pixelBytes = null;

        private readonly BitmapPixelFormat _pixelFormat = BitmapPixelFormat.Rgba8;
        public BitmapPixelFormat PixelFormat
        {
            get { return _pixelFormat; }
        }

        public uint Width
        {
            get { return _clipWidth; }
        }

        public uint Height
        {
            get { return _clipHeight; }
        }

        public uint TotalPixels
        {
            get { return _clipPixels; }
        }

        public Color GetPixel(uint x, uint y)
        {
            x += _clipLeft;
            y += _clipTop;
            if (x >= _clipLeft + _clipWidth || y >= _clipTop + _clipHeight)
            {
                throw new Exception("Pixel requested outside of bounds");
            }
            uint offset = (y * (_imageWidth << 2)) + (x << 2);
            if (_pixelFormat == BitmapPixelFormat.Bgra8)
            {
                return Color.FromArgb(_pixelBytes[offset + 3], _pixelBytes[offset + 2], _pixelBytes[offset + 1], _pixelBytes[offset]);
            }
            else
            {
                return Color.FromArgb(_pixelBytes[offset + 3], _pixelBytes[offset], _pixelBytes[offset + 1], _pixelBytes[offset + 2]);
            }
        }

        public void PerPixelAction(Action<Color, uint, uint> action)
        {
            for (uint x = 0; x < _clipWidth; x++)
            {
                for (uint y = 0; y < _clipHeight; y++)
                {
                    action(GetPixel(x, y), x, y);
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Editors/BoolEditor.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.Editors
{
    public class BoolEditor : Control
    {
        public BoolEditor()
        {
            this.DefaultStyleKey = typeof(BoolEditor);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var h = Header;
            if (h != null)
            {
                var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
                if (headerContentPresenter != null)
                {
                    headerContentPresenter.Visibility = h == null ? Visibility.Collapsed : Visibility.Visible;
                }
            }
        }

        #region ValueProperty

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(bool), typeof(BoolEditor), new PropertyMetadata(false, new PropertyChangedCallback(OnValuePropertyChanged)));

        private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BoolEditor target = d as BoolEditor;
            if (target != null)
            {
                target.OnValueChanged((bool)e.OldValue, (bool)e.NewValue);
            }
        }

        private void OnValueChanged(bool oldValue, bool newValue)
        {
            DisplayValue = newValue.ToString();
        }

        public bool Value
        {
            get { return (bool)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        #endregion

        #region DisplayValueProperty

        public static DependencyProperty DisplayValueProperty = DependencyProperty.Register("DisplayValue", typeof(string), typeof(BoolEditor), new PropertyMetadata("False"));

        public string DisplayValue
        {
            get { return GetValue(DisplayValueProperty) as string; }
            set { SetValue(DisplayValueProperty, value); }
        }

        #endregion

        #region HeaderProperty

        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(BoolEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnHeaderPropertyChanged)));

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is BoolEditor target)
            {
                target.OnHeaderPropertyChanged(e.OldValue, e.NewValue);
            }
        }

        private void OnHeaderPropertyChanged(object oldVal, object newVal)
        {
            var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
            if (headerContentPresenter != null)
            {
                headerContentPresenter.Visibility = newVal == null ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        #endregion

        #region HeaderTemplateProperty

        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(BoolEditor), new PropertyMetadata(null));

        public DataTemplate HeaderTemplate
        {
            get { return GetValue(HeaderTemplateProperty) as DataTemplate; }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/Editors/EnumSelectionAdapter.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace FluentEditorShared.Editors
{
    // Sometimes it is easier to handle enums on the ViewModel side of things rather than using EnumEditor as a control. Depends on the situation.
    public class EnumSelectionAdapter : INotifyPropertyChanged
    {
        public EnumSelectionAdapter(Type enumType)
        {
            _enumType = enumType;
            _availableStrings = Enum.GetNames(_enumType);
            _selectedString = _availableStrings[0];
        }

        private string _caption = null;
        public string Caption
        {
            get { return _caption; }
            set
            {
                if (_caption != value)
                {
                    _caption = value;
                    RaisePropertyChangedFromSource();
                }
            }
        }

        private readonly Type _enumType = null;
        public Type EnumType
        {
            get { return _enumType; }
        }

        private readonly string[] _availableStrings = null;
        public string[] AvailableStrings
        {
            get { return _availableStrings; }
        }

        private string _selectedString = null;
        public string SelectedString
        {
            get { return _selectedString; }
            set
            {
                if (_selectedString != value)
                {
                    _selectedString = value;
                    RaisePropertyChangedFromSource();

                    SelectionChanged?.Invoke(this);
                }
            }
        }

        public event Action<EnumSelectionAdapter> SelectionChanged;

        public T GetSelectedValue<T>() where T : struct
        {
            T output;
            if (Enum.TryParse<T>(_selectedString, out output))
            {
                return output;
            }
            return default(T);
        }

        public void SetSelectedValue<T>(T value) where T : struct
        {
            if (typeof(T) != _enumType)
            {
                return;
            }
            SelectedString = value.ToString();
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string name)
        {
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
            {
                h(this, new PropertyChangedEventArgs(name));
            }
        }

        private void RaisePropertyChangedFromSource([CallerMemberName] string name = null)
        {
            RaisePropertyChanged(name);
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/Shadow/Shadow.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Numerics;
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;

namespace FluentEditorShared.Shadow
{
    public sealed partial class Shadow : UserControl
    {
        public Shadow()
        {
            this.InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            InitializeShadow();
            ResizeShadow();
        }

        private void UserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            DisposeShadow();
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ResizeShadow();
        }

        #region ElevationProperty

        public static DependencyProperty ElevationProperty = DependencyProperty.Register("Elevation", typeof(double), typeof(Shadow), new PropertyMetadata((double)1, new PropertyChangedCallback(OnElevationPropertyChanged)));

        private static void OnElevationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is Shadow target)
            {
                target.OnElevationChanged((double)e.OldValue, (double)e.NewValue);
            }
        }

        private void OnElevationChanged(double oldValue, double newValue)
        {
            UpdateShadowValues();
        }

        public double Elevation
        {
            get { return (double)GetValue(ElevationProperty); }
            set { SetValue(ElevationProperty, value); }
        }

        #endregion

        #region ColorProperty

        public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(Shadow), new PropertyMetadata(Colors.Black, new PropertyChangedCallback(OnColorPropertyChanged)));

        private static void OnColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is Shadow target)
            {
                target.OnColorChanged((Color)e.OldValue, (Color)e.NewValue);
            }
        }

        private void OnColorChanged(Color oldValue, Color newValue)
        {
            UpdateShadowValues();
        }

        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        #endregion

        private ContainerVisual _shadowContainer;
        private DropShadow _shadowDirectional;
        private DropShadow _shadowAmbient;
        private SpriteVisual _shadowDirectionalVisual;
        private SpriteVisual _shadowAmbientVisual;

        private void InitializeShadow()
        {
            if (_shadowDirectional != null)
            {
                DisposeShadow();
            }

            var compositor = Window.Current.Compositor;

            _shadowContainer = compositor.CreateContainerVisual();

            _shadowAmbientVisual = compositor.CreateSpriteVisual();
            _shadowAmbient = compositor.CreateDropShadow();
            _shadowAmbientVisual.Shadow = _shadowAmbient;

            _shadowDirectionalVisual = compositor.CreateSpriteVisual();
            _shadowDirectional = compositor.CreateDropShadow();
            _shadowDirectionalVisual.Shadow = _shadowDirectional;

            _shadowContainer.Children.InsertAtTop(_shadowAmbientVisual);
            _shadowContainer.Children.InsertAtTop(_shadowDirectionalVisual);
            ElementCompositionPreview.SetElementChildVisual(PlaceholderElement, _shadowContainer);

            UpdateShadowValues();
        }

        private void DisposeShadow()
        {
            if (_shadowAmbient != null)
            {
                _shadowAmbient.Dispose();
                _shadowAmbient = null;
            }
            if (_shadowAmbientVisual != null)
            {
                _shadowAmbientVisual.Dispose();
                _shadowAmbientVisual = null;
            }
            if (_shadowDirectional != null)
            {
                _shadowDirectional.Dispose();
                _shadowDirectional = null;
            }
            if (_shadowDirectionalVisual != null)
            {
                _shadowDirectionalVisual.Dispose();
                _shadowDirectionalVisual = null;
            }
        }

        private void ResizeShadow()
        {
            if (_shadowDirectionalVisual != null)
            {
                _shadowDirectionalVisual.Size = new Vector2((float)PlaceholderElement.ActualWidth, (float)PlaceholderElement.ActualHeight);
            }
            if (_shadowAmbientVisual != null)
            {
                _shadowAmbientVisual.Size = new Vector2((float)PlaceholderElement.ActualWidth, (float)PlaceholderElement.ActualHeight);
            }
        }
        private void UpdateShadowValues()
        {
            var e = (float)Elevation;
            var o = e < 24 ? 1 : 0.6f;

            if (_shadowDirectionalVisual != null)
            {
                _shadowDirectional.BlurRadius = (e * 0.9f);
                _shadowDirectional.Opacity = o * 0.22f;
                _shadowDirectional.Offset = new Vector3(0, e * 0.4f, 0);
                _shadowDirectional.Color = Color;
            }
            if (_shadowAmbientVisual != null)
            {
                _shadowAmbient.BlurRadius = (e * 0.225f);
                _shadowAmbient.Opacity = o * 0.18f;
                _shadowAmbient.Offset = new Vector3(0, e * 0.0075f, 0);
                _shadowAmbient.Color = Color;
            }
        }
    }
}



<|start_filename|>FluentEditorShared/Utils/PixelBlob.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public class PixelBlob : IPixelBlob
    {
        #region Helper for loading from a stream

        public static async Task<PixelBlob> LoadPixelsFromStream(IRandomAccessStream source)
        {
            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(source);

            if (decoder.BitmapPixelFormat != BitmapPixelFormat.Rgba8 && decoder.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
            {
                throw new Exception("Unsupported pixel format");
            }

            var pixelData = await decoder.GetPixelDataAsync();
            var pixelBytes = pixelData.DetachPixelData();

            return new PixelBlob(pixelBytes, decoder.BitmapPixelFormat, decoder.OrientedPixelWidth, decoder.OrientedPixelHeight);
        }

        #endregion

        // The pixelBytes array is never changed by this class
        public PixelBlob(byte[] pixelBytes, BitmapPixelFormat pixelFormat, uint width, uint height)
        {
            if (pixelFormat != BitmapPixelFormat.Rgba8 && pixelFormat != BitmapPixelFormat.Bgra8)
            {
                throw new Exception("Unsupported pixel format");
            }
            if ((long)width * (long)height * 4L >= (long)int.MaxValue)
            {
                throw new Exception("Image too large");
            }
            uint expectedSize = (width * height) * 4;
            if (pixelBytes.Length != expectedSize)
            {
                throw new Exception("Pixel array length does not match dimensions");
            }
            _pixelBytes = pixelBytes;
            _pixelFormat = pixelFormat;
            _width = width;
            _height = height;
            _totalPixels = _width * _height;
        }

        private readonly byte[] _pixelBytes = null;

        private readonly BitmapPixelFormat _pixelFormat = BitmapPixelFormat.Rgba8;
        public BitmapPixelFormat PixelFormat
        {
            get { return _pixelFormat; }
        }

        private readonly uint _width = 0;
        public uint Width
        {
            get { return _width; }
        }

        private readonly uint _height = 0;
        public uint Height
        {
            get { return _height; }
        }

        private readonly uint _totalPixels = 0;
        public uint TotalPixels
        {
            get { return _totalPixels; }
        }

        public Color GetPixel(uint x, uint y)
        {
            if (x >= _width || y >= _height)
            {
                throw new Exception("Pixel requested outside of bounds");
            }
            uint offset = (y * (_width << 2)) + (x << 2);
            if (_pixelFormat == BitmapPixelFormat.Bgra8)
            {
                return Color.FromArgb(_pixelBytes[offset + 3], _pixelBytes[offset + 2], _pixelBytes[offset + 1], _pixelBytes[offset]);
            }
            else
            {
                return Color.FromArgb(_pixelBytes[offset + 3], _pixelBytes[offset], _pixelBytes[offset + 1], _pixelBytes[offset + 2]);
            }
        }

        public void PerPixelAction(Action<Color, uint, uint> action)
        {
            for (uint y = 0; y < _height; y++)
            {
                for (uint x = 0; x < _height; x++)
                {
                    action(GetPixel(x, y), x, y);
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/MessageBus/IMessageBus.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace FluentEditorShared.MessageBus
{
    public interface IMessageBusListener
    {
        void OnMessage<T>(in T message) where T : struct;
    }

    public interface IReadOnlyMessageBus
    {
        // The listener is stored as a WeakReference
        void AddListener<T>(IMessageBusListener listener) where T : struct;
        // The delegate d is stored as a strong reference. It is up to the caller to make sure that the delegate isn't strongly capturing anything it shouldn't.
        void AddListener<T>(Action<T> d) where T : struct;
        void RemoveListener<T>(IMessageBusListener listener) where T : struct;
        void RemoveListener<T>(Action<T> d) where T : struct;
        void PruneListeners();
    }

    public interface IMessageBus
    {
        // The listener is stored as a WeakReference
        void AddListener<T>(IMessageBusListener listener) where T : struct;
        // The delegate d is stored as a strong reference. It is up to the caller to make sure that the delegate isn't strongly capturing anything it shouldn't.
        void AddListener<T>(Action<T> d) where T : struct;
        void RemoveListener<T>(IMessageBusListener listener) where T : struct;
        void RemoveListener<T>(Action<T> d) where T : struct;
        void PruneListeners();

        void BroadcastMessage<T>(in T message) where T : struct;
    }
}


<|start_filename|>FluentEditor/ControlPalette/Model/Preset.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using Windows.Data.Json;
using Windows.UI;
using FluentEditorShared.Utils;
using FluentEditorShared.ColorPalette;

namespace FluentEditor.ControlPalette.Model
{
    public class Preset
    {
        public static Preset Parse(JsonObject data, string id = null, string name = null)
        {
            if(id == null)
            {
                id = data["Id"].GetString();
            }
            if (name == null)
            {
                name = data["Name"].GetString();
            }
            Color lightRegionColor = data["LightRegionColor"].GetColor();
            Color darkRegionColor = data["DarkRegionColor"].GetColor();
            Color lightBaseColor = data["LightBaseColor"].GetColor();
            Color darkBaseColor = data["DarkBaseColor"].GetColor();
            Color lightPrimaryColor = data["LightPrimaryColor"].GetColor();
            Color darkPrimaryColor = data["DarkPrimaryColor"].GetColor();

            Dictionary<int, Color> lightBaseOverrides = new Dictionary<int, Color>();
            if (data.ContainsKey("LightBaseOverrides"))
            {
                var lightBaseOverridesNode = data["LightBaseOverrides"].GetArray();
                foreach (var v in lightBaseOverridesNode)
                {
                    var node = v.GetObject();

                    int index = node["Index"].GetInt();
                    Color color = node["Color"].GetColor();
                    lightBaseOverrides.Add(index, color);
                }
            }

            Dictionary<int, Color> darkBaseOverrides = new Dictionary<int, Color>();
            if (data.ContainsKey("DarkBaseOverrides"))
            {
                var darkBaseOverridesNode = data["DarkBaseOverrides"].GetArray();
                foreach (var v in darkBaseOverridesNode)
                {
                    var node = v.GetObject();

                    int index = node["Index"].GetInt();
                    Color color = node["Color"].GetColor();
                    darkBaseOverrides.Add(index, color);
                }
            }

            Dictionary<int, Color> lightPrimaryOverrides = new Dictionary<int, Color>();
            if (data.ContainsKey("LightPrimaryOverrides"))
            {
                var lightPrimaryOverridesNode = data["LightPrimaryOverrides"].GetArray();
                foreach (var v in lightPrimaryOverridesNode)
                {
                    var node = v.GetObject();

                    int index = node["Index"].GetInt();
                    Color color = node["Color"].GetColor();
                    lightPrimaryOverrides.Add(index, color);
                }
            }

            Dictionary<int, Color> darkPrimaryOverrides = new Dictionary<int, Color>();
            if (data.ContainsKey("DarkPrimaryOverrides"))
            {
                var darkPrimaryOverridesNode = data["DarkPrimaryOverrides"].GetArray();
                foreach (var v in darkPrimaryOverridesNode)
                {
                    var node = v.GetObject();

                    int index = node["Index"].GetInt();
                    Color color = node["Color"].GetColor();
                    darkPrimaryOverrides.Add(index, color);
                }
            }

            return new Preset(id, name, lightRegionColor, darkRegionColor, lightBaseColor, lightBaseOverrides, darkBaseColor, darkBaseOverrides, lightPrimaryColor, lightPrimaryOverrides, darkPrimaryColor, darkPrimaryOverrides);
        }

        public static JsonObject Serialize(Preset preset)
        {
            JsonObject data = new JsonObject();
            if (!string.IsNullOrEmpty(preset.Id))
            {
                data["Id"] = JsonValue.CreateStringValue(preset.Id);
            }
            if (!string.IsNullOrEmpty(preset.Name))
            {
                data["Name"] = JsonValue.CreateStringValue(preset.Name);
            }
            data["LightRegionColor"] = JsonValue.CreateStringValue(preset.LightRegionColor.ToString());
            data["DarkRegionColor"] = JsonValue.CreateStringValue(preset.DarkRegionColor.ToString());
            data["LightBaseColor"] = JsonValue.CreateStringValue(preset.LightBaseColor.ToString());
            data["DarkBaseColor"] = JsonValue.CreateStringValue(preset.DarkBaseColor.ToString());
            data["LightPrimaryColor"] = JsonValue.CreateStringValue(preset.LightPrimaryColor.ToString());
            data["DarkPrimaryColor"] = JsonValue.CreateStringValue(preset.DarkPrimaryColor.ToString());

            var lightBaseOverridesNode = new JsonArray();
            foreach (int index in preset.LightBaseOverrides.Keys)
            {
                JsonObject node = new JsonObject();
                node["Index"] = JsonValue.CreateNumberValue(index);
                node["Color"] = JsonValue.CreateStringValue(preset.LightBaseOverrides[index].ToString());
                lightBaseOverridesNode.Add(node);
            }
            data["LightBaseOverrides"] = lightBaseOverridesNode;

            var darkBaseOverridesNode = new JsonArray();
            foreach (int index in preset.DarkBaseOverrides.Keys)
            {
                JsonObject node = new JsonObject();
                node["Index"] = JsonValue.CreateNumberValue(index);
                node["Color"] = JsonValue.CreateStringValue(preset.DarkBaseOverrides[index].ToString());
                darkBaseOverridesNode.Add(node);
            }
            data["DarkBaseOverrides"] = darkBaseOverridesNode;

            var lightPrimaryOverridesNode = new JsonArray();
            foreach (int index in preset.LightPrimaryOverrides.Keys)
            {
                JsonObject node = new JsonObject();
                node["Index"] = JsonValue.CreateNumberValue(index);
                node["Color"] = JsonValue.CreateStringValue(preset.LightPrimaryOverrides[index].ToString());
                lightPrimaryOverridesNode.Add(node);
            }
            data["LightPrimaryOverrides"] = lightPrimaryOverridesNode;

            var darkPrimaryOverridesNode = new JsonArray();
            foreach (int index in preset.DarkPrimaryOverrides.Keys)
            {
                JsonObject node = new JsonObject();
                node["Index"] = JsonValue.CreateNumberValue(index);
                node["Color"] = JsonValue.CreateStringValue(preset.DarkPrimaryOverrides[index].ToString());
                darkPrimaryOverridesNode.Add(node);
            }
            data["DarkPrimaryOverrides"] = darkPrimaryOverridesNode;

            return data;
        }

        public Preset(string id, string name, Color lightRegionColor, Color darkRegionColor, Color lightBaseColor, Dictionary<int, Color> lightBaseOverrides, Color darkBaseColor, Dictionary<int, Color> darkBaseOverrides, Color lightPrimaryColor, Dictionary<int, Color> lightPrimaryOverrides, Color darkPrimaryColor, Dictionary<int, Color> darkPrimaryOverrides)
        {
            _id = id;
            _name = name;
            _lightRegionColor = lightRegionColor;
            _darkRegionColor = darkRegionColor;
            _lightBaseColor = lightBaseColor;
            _lightBaseOverrides = lightBaseOverrides;
            _darkBaseColor = darkBaseColor;
            _darkBaseOverrides = darkBaseOverrides;
            _lightPrimaryColor = lightPrimaryColor;
            _lightPrimaryOverrides = lightPrimaryOverrides;
            _darkPrimaryColor = darkPrimaryColor;
            _darkPrimaryOverrides = darkPrimaryOverrides;
        }

        public Preset(string id, string name, IControlPaletteModel model)
        {
            _id = id;
            _name = name;

            _lightRegionColor = model.LightRegion.ActiveColor;
            _darkRegionColor = model.DarkRegion.ActiveColor;

            _lightBaseColor = model.LightBase.BaseColor.ActiveColor;
            _lightBaseOverrides = new Dictionary<int, Color>();
            for (int i = 0; i < model.LightBase.Palette.Count; i++)
            {
                if (model.LightBase.Palette[i].UseCustomColor)
                {
                    _lightBaseOverrides.Add(i, model.LightBase.Palette[i].ActiveColor);
                }
            }

            _darkBaseColor = model.DarkBase.BaseColor.ActiveColor;
            _darkBaseOverrides = new Dictionary<int, Color>();
            for (int i = 0; i < model.DarkBase.Palette.Count; i++)
            {
                if (model.DarkBase.Palette[i].UseCustomColor)
                {
                    _darkBaseOverrides.Add(i, model.DarkBase.Palette[i].ActiveColor);
                }
            }

            _lightPrimaryColor = model.LightPrimary.BaseColor.ActiveColor;
            _lightPrimaryOverrides = new Dictionary<int, Color>();
            for (int i = 0; i < model.LightPrimary.Palette.Count; i++)
            {
                if (model.LightPrimary.Palette[i].UseCustomColor)
                {
                    _lightPrimaryOverrides.Add(i, model.LightPrimary.Palette[i].ActiveColor);
                }
            }

            _darkPrimaryColor = model.DarkPrimary.BaseColor.ActiveColor;
            _darkPrimaryOverrides = new Dictionary<int, Color>();
            for (int i = 0; i < model.DarkPrimary.Palette.Count; i++)
            {
                if (model.DarkPrimary.Palette[i].UseCustomColor)
                {
                    _darkPrimaryOverrides.Add(i, model.DarkPrimary.Palette[i].ActiveColor);
                }
            }
        }

        private readonly string _id;
        public string Id { get { return _id; } }

        private readonly string _name;
        public string Name { get { return _name; } }

        private readonly Color _lightRegionColor;
        public Color LightRegionColor { get { return _lightRegionColor; } }

        private readonly Color _darkRegionColor;
        public Color DarkRegionColor { get { return _darkRegionColor; } }

        private readonly Color _lightBaseColor;
        public Color LightBaseColor { get { return _lightBaseColor; } }

        private readonly Dictionary<int, Color> _lightBaseOverrides;
        public Dictionary<int, Color> LightBaseOverrides { get { return _lightBaseOverrides; } }

        private readonly Color _darkBaseColor;
        public Color DarkBaseColor { get { return _darkBaseColor; } }

        private readonly Dictionary<int, Color> _darkBaseOverrides;
        public Dictionary<int, Color> DarkBaseOverrides { get { return _darkBaseOverrides; } }

        private readonly Color _lightPrimaryColor;
        public Color LightPrimaryColor { get { return _lightPrimaryColor; } }

        private readonly Dictionary<int, Color> _lightPrimaryOverrides;
        public Dictionary<int, Color> LightPrimaryOverrides { get { return _lightPrimaryOverrides; } }

        private readonly Color _darkPrimaryColor;
        public Color DarkPrimaryColor { get { return _darkPrimaryColor; } }

        private readonly Dictionary<int, Color> _darkPrimaryOverrides;
        public Dictionary<int, Color> DarkPrimaryOverrides { get { return _darkPrimaryOverrides; } }

        public bool IsPresetActive(IControlPaletteModel model)
        {
            if (model == null)
            {
                return false;
            }
            if (model.LightRegion.ActiveColor != _lightRegionColor)
            {
                return false;
            }
            if (model.DarkRegion.ActiveColor != _darkRegionColor)
            {
                return false;
            }
            if (model.LightBase.BaseColor.ActiveColor != _lightBaseColor)
            {
                return false;
            }
            if (model.DarkBase.BaseColor.ActiveColor != _darkBaseColor)
            {
                return false;
            }
            if (model.LightPrimary.BaseColor.ActiveColor != _lightPrimaryColor)
            {
                return false;
            }
            if (model.DarkPrimary.BaseColor.ActiveColor != _darkPrimaryColor)
            {
                return false;
            }
            if (!CompareOverrides(_lightBaseOverrides, model.LightBase.Palette))
            {
                return false;
            }
            if (!CompareOverrides(_darkBaseOverrides, model.DarkBase.Palette))
            {
                return false;
            }
            if (!CompareOverrides(_lightPrimaryOverrides, model.LightPrimary.Palette))
            {
                return false;
            }
            if (!CompareOverrides(_darkPrimaryOverrides, model.DarkPrimary.Palette))
            {
                return false;
            }

            return true;
        }

        private bool CompareOverrides(Dictionary<int, Color> presetDictionary, IReadOnlyList<EditableColorPaletteEntry> palette)
        {
            if (presetDictionary == null || palette == null)
            {
                return false;
            }

            for (int i = 0; i < palette.Count; i++)
            {
                if (palette[i].UseCustomColor)
                {
                    if (!presetDictionary.ContainsKey(i) || presetDictionary[i] != palette[i].ActiveColor)
                    {
                        return false;
                    }
                }
            }

            var keys = presetDictionary.Keys;
            foreach (var index in keys)
            {
                if (index >= palette.Count || index < 0)
                {
                    return false;
                }
                if (!palette[index].UseCustomColor || palette[index].ActiveColor != presetDictionary[index])
                {
                    return false;
                }
            }

            return true;
        }
    }
}


<|start_filename|>FluentEditorShared/FilePickerAdapter.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.Storage.Pickers;

namespace FluentEditorShared
{
    public static class FilePickerAdapters
    {
        public static async Task<StorageFile> ShowLoadFilePicker(string[] filters = null, PickerLocationId startLocation = PickerLocationId.PicturesLibrary, PickerViewMode viewMode = PickerViewMode.Thumbnail, bool addToRecent = false, bool addToFuture = false)
        {
            var picker = new FileOpenPicker();
            picker.SuggestedStartLocation = startLocation;
            picker.ViewMode = viewMode;
            if (filters != null)
            {
                foreach (string filter in filters)
                {
                    picker.FileTypeFilter.Add(filter);
                }
            }
            StorageFile file = await picker.PickSingleFileAsync();
            if (file != null)
            {
                if (addToRecent)
                {
                    StorageApplicationPermissions.MostRecentlyUsedList.Add(file);
                }
                if (addToFuture)
                {
                    StorageApplicationPermissions.FutureAccessList.Add(file);
                }
                return file;
            }
            else
            {
                return null;
            }
        }

        public static async Task<StorageFile> ShowSaveFilePicker(string suggestedFileName = null, string defaultFileExtension = null, Tuple<string, IList<string>>[] fileExtensions = null, string enterpriseId = null, PickerLocationId startLocation = PickerLocationId.PicturesLibrary, bool addToRecent = false, bool addToFuture = false, string commmitButtonText = null)
        {
            var picker = new FileSavePicker();
            picker.SuggestedStartLocation = startLocation;
            if (commmitButtonText != null)
            {
                picker.CommitButtonText = commmitButtonText;
            }
            if (defaultFileExtension != null)
            {
                picker.DefaultFileExtension = defaultFileExtension;
            }
            if (enterpriseId != null)
            {
                picker.EnterpriseId = enterpriseId;
            }
            if (suggestedFileName != null)
            {
                picker.SuggestedFileName = suggestedFileName;
            }
            if (fileExtensions != null)
            {
                foreach (var ext in fileExtensions)
                {
                    picker.FileTypeChoices.Add(ext.Item1, ext.Item2);
                }
            }

            StorageFile file = await picker.PickSaveFileAsync();

            if (file != null)
            {
                if (addToRecent)
                {
                    StorageApplicationPermissions.MostRecentlyUsedList.Add(file);
                }
                if (addToFuture)
                {
                    StorageApplicationPermissions.FutureAccessList.Add(file);
                }
                return file;
            }
            else
            {
                return null;
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Editors/ColorEditor.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;

namespace FluentEditorShared.Editors
{
    public class ColorEditor : Control
    {
        public ColorEditor()
        {
            this.DefaultStyleKey = typeof(ColorEditor);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var h = Header;
            if (h != null)
            {
                var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
                if (headerContentPresenter != null)
                {
                    headerContentPresenter.Visibility = h == null ? Visibility.Collapsed : Visibility.Visible;
                }
            }
        }

        // Dependency properties can safely be assumed to be single threaded so this is sufficient for dealing with loopbacks on property changed
        private bool _internalValueChanging = false;

        private void UpdateProperties(Color color)
        {
            ValueString = Utils.ColorUtils.FormatColorString(color, ColorStringFormat, Precision);
            var b = ValueBrush;
            if (b == null)
            {
                ValueBrush = new SolidColorBrush(color);
            }
            else
            {
                b.Color = color;
            }
            ValueRed = color.R;
            ValueRedString = color.R.ToString();
            ValueGreen = color.G;
            ValueGreenString = color.G.ToString();
            ValueBlue = color.B;
            ValueBlueString = color.B.ToString();
            if (UseAlpha)
            {
                ValueAlpha = color.A;
                ValueAlphaString = color.A.ToString();
            }
            else
            {
                ValueAlpha = 255;
                ValueAlphaString = "255";
            }
        }

        #region ValueColor

        public static readonly DependencyProperty ValueColorProperty = DependencyProperty.Register("ValueColor", typeof(Color), typeof(ColorEditor), new PropertyMetadata(Colors.Black, new PropertyChangedCallback(OnValueColorPropertyChanged)));

        private static void OnValueColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueColorChanged((Color)e.OldValue, (Color)e.NewValue);
            }
        }

        private void OnValueColorChanged(Color oldValue, Color newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                UpdateProperties(newValue);

                _internalValueChanging = false;
            }
        }

        public Color ValueColor
        {
            get { return (Color)GetValue(ValueColorProperty); }
            set { SetValue(ValueColorProperty, value); }
        }

        #endregion

        #region ValueStringProperty

        public static readonly DependencyProperty ValueStringProperty = DependencyProperty.Register("ValueString", typeof(string), typeof(ColorEditor), new PropertyMetadata("000000", new PropertyChangedCallback(OnValueStringPropertyChanged)));

        private static void OnValueStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                Color c;
                try
                {
                    var boxedColor = XamlBindingHelper.ConvertValue(typeof(Color), newValue);
                    if (boxedColor == null)
                    {
                        return;
                    }
                    c = (Color)boxedColor;
                }
                catch
                {
                    return;
                }

                _internalValueChanging = true;

                UpdateProperties(c);

                _internalValueChanging = false;
            }
        }

        public string ValueString
        {
            get { return GetValue(ValueStringProperty) as string; }
            set { SetValue(ValueStringProperty, value); }
        }

        #endregion

        #region ValueBrushProperty

        public static DependencyProperty ValueBrushProperty = DependencyProperty.Register("ValueBrush", typeof(SolidColorBrush), typeof(ColorEditor), new PropertyMetadata(new SolidColorBrush(Colors.Black), new PropertyChangedCallback(OnValueBrushPropertyChanged)));

        private static void OnValueBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueBrushChanged(e.OldValue as SolidColorBrush, e.NewValue as SolidColorBrush);
            }
        }

        private void OnValueBrushChanged(SolidColorBrush oldValue, SolidColorBrush newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;
                if (newValue == null)
                {
                    ValueBrush = new SolidColorBrush(ValueColor);
                }
                else
                {
                    var b = ValueBrush;
                    if (b != null)
                    {
                        UpdateProperties(b.Color);
                    }
                }

                _internalValueChanging = false;
            }
        }

        public SolidColorBrush ValueBrush
        {
            get { return GetValue(ValueBrushProperty) as SolidColorBrush; }
            set { SetValue(ValueBrushProperty, value); }
        }

        #endregion

        #region ValueRed

        public static DependencyProperty ValueRedProperty = DependencyProperty.Register("ValueRed", typeof(byte), typeof(ColorEditor), new PropertyMetadata((byte)0, new PropertyChangedCallback(OnValueRedPropertyChanged)));

        private static void OnValueRedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueRedChanged((byte)e.OldValue, (byte)e.NewValue);
            }
        }

        private void OnValueRedChanged(byte oldValue, byte newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                var oldColor = ValueColor;
                UpdateProperties(Color.FromArgb(oldColor.A, newValue, oldColor.G, oldColor.B));

                _internalValueChanging = false;
            }
        }

        public byte ValueRed
        {
            get { return (byte)GetValue(ValueRedProperty); }
            set { SetValue(ValueRedProperty, value); }
        }

        #endregion

        #region ValueRedString

        public static DependencyProperty ValueRedStringProperty = DependencyProperty.Register("ValueRedString", typeof(string), typeof(ColorEditor), new PropertyMetadata("0", new PropertyChangedCallback(OnValueRedStringPropertyChanged)));

        private static void OnValueRedStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueRedStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueRedStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                if (string.IsNullOrEmpty(newValue))
                {
                    return;
                }

                _internalValueChanging = true;
                byte newByte;
                if (byte.TryParse(newValue, out newByte))
                {
                    var oldColor = ValueColor;
                    UpdateProperties(Color.FromArgb(oldColor.A, newByte, oldColor.G, oldColor.B));
                }

                _internalValueChanging = false;
            }
        }

        public string ValueRedString
        {
            get { return GetValue(ValueRedStringProperty) as string; }
            set { SetValue(ValueRedStringProperty, value); }
        }

        #endregion

        #region ValueGreen

        public static DependencyProperty ValueGreenProperty = DependencyProperty.Register("ValueGreen", typeof(byte), typeof(ColorEditor), new PropertyMetadata((byte)0, new PropertyChangedCallback(OnValueGreenPropertyChanged)));

        private static void OnValueGreenPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueGreenChanged((byte)e.OldValue, (byte)e.NewValue);
            }
        }

        private void OnValueGreenChanged(byte oldValue, byte newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                var oldColor = ValueColor;
                UpdateProperties(Color.FromArgb(oldColor.A, oldColor.R, newValue, oldColor.B));

                _internalValueChanging = false;
            }
        }

        public byte ValueGreen
        {
            get { return (byte)GetValue(ValueGreenProperty); }
            set { SetValue(ValueGreenProperty, value); }
        }

        #endregion

        #region ValueGreenString

        public static DependencyProperty ValueGreenStringProperty = DependencyProperty.Register("ValueGreenString", typeof(string), typeof(ColorEditor), new PropertyMetadata("0", new PropertyChangedCallback(OnValueGreenStringPropertyChanged)));

        private static void OnValueGreenStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueGreenStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueGreenStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                if (string.IsNullOrEmpty(newValue))
                {
                    return;
                }

                _internalValueChanging = true;
                byte newByte;
                if (byte.TryParse(newValue, out newByte))
                {
                    var oldColor = ValueColor;
                    UpdateProperties(Color.FromArgb(oldColor.A, oldColor.R, newByte, oldColor.B));
                }

                _internalValueChanging = false;
            }
        }

        public string ValueGreenString
        {
            get { return GetValue(ValueGreenStringProperty) as string; }
            set { SetValue(ValueGreenStringProperty, value); }
        }

        #endregion

        #region ValueBlue

        public static DependencyProperty ValueBlueProperty = DependencyProperty.Register("ValueBlue", typeof(byte), typeof(ColorEditor), new PropertyMetadata((byte)0, new PropertyChangedCallback(OnValueBluePropertyChanged)));

        private static void OnValueBluePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueBlueChanged((byte)e.OldValue, (byte)e.NewValue);
            }
        }

        private void OnValueBlueChanged(byte oldValue, byte newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                var oldColor = ValueColor;
                UpdateProperties(Color.FromArgb(oldColor.A, oldColor.R, oldColor.G, newValue));

                _internalValueChanging = false;
            }
        }

        public byte ValueBlue
        {
            get { return (byte)GetValue(ValueBlueProperty); }
            set { SetValue(ValueBlueProperty, value); }
        }

        #endregion

        #region ValueBlueString

        public static DependencyProperty ValueBlueStringProperty = DependencyProperty.Register("ValueBlueString", typeof(string), typeof(ColorEditor), new PropertyMetadata("0", new PropertyChangedCallback(OnValueBlueStringPropertyChanged)));

        private static void OnValueBlueStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueBlueStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueBlueStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                if (string.IsNullOrEmpty(newValue))
                {
                    return;
                }

                _internalValueChanging = true;
                byte newByte;
                if (byte.TryParse(newValue, out newByte))
                {
                    var oldColor = ValueColor;
                    UpdateProperties(Color.FromArgb(oldColor.A, oldColor.R, oldColor.G, newByte));
                }

                _internalValueChanging = false;
            }
        }

        public string ValueBlueString
        {
            get { return GetValue(ValueBlueStringProperty) as string; }
            set { SetValue(ValueBlueStringProperty, value); }
        }

        #endregion

        #region ValueAlpha

        public static DependencyProperty ValueAlphaProperty = DependencyProperty.Register("ValueAlpha", typeof(byte), typeof(ColorEditor), new PropertyMetadata((byte)255, new PropertyChangedCallback(OnValueAlphaPropertyChanged)));

        private static void OnValueAlphaPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueAlphaChanged((byte)e.OldValue, (byte)e.NewValue);
            }
        }

        private void OnValueAlphaChanged(byte oldValue, byte newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                var oldColor = ValueColor;
                UpdateProperties(Color.FromArgb(newValue, oldColor.R, oldColor.G, oldColor.B));

                _internalValueChanging = false;
            }
        }

        public byte ValueAlpha
        {
            get { return (byte)GetValue(ValueAlphaProperty); }
            set { SetValue(ValueAlphaProperty, value); }
        }

        #endregion

        #region ValueAlphaString

        public static DependencyProperty ValueAlphaStringProperty = DependencyProperty.Register("ValueAlphaString", typeof(string), typeof(ColorEditor), new PropertyMetadata("255", new PropertyChangedCallback(OnValueAlphaStringPropertyChanged)));

        private static void OnValueAlphaStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnValueAlphaStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueAlphaStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                if (string.IsNullOrEmpty(newValue))
                {
                    return;
                }

                _internalValueChanging = true;
                byte newByte;
                if (byte.TryParse(newValue, out newByte))
                {
                    var oldColor = ValueColor;
                    UpdateProperties(Color.FromArgb(newByte, oldColor.R, oldColor.G, oldColor.B));
                }

                _internalValueChanging = false;
            }
        }

        public string ValueAlphaString
        {
            get { return GetValue(ValueAlphaStringProperty) as string; }
            set { SetValue(ValueAlphaStringProperty, value); }
        }

        #endregion

        // could easily add more properties like this for HSL or whatever color space is needed

        #region UseAlphaProperty

        public static readonly DependencyProperty UseAlphaProperty = DependencyProperty.Register("UseAlpha", typeof(bool), typeof(ColorEditor), new PropertyMetadata(true, new PropertyChangedCallback(OnUseAlphaPropertyChanged)));

        private static void OnUseAlphaPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnUseAlphaChanged((bool)e.OldValue, (bool)e.NewValue);
            }
        }

        private void OnUseAlphaChanged(bool oldValue, bool newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                if(!newValue)
                {
                    var oldColor = ValueColor;
                    UpdateProperties(Color.FromArgb(255, oldColor.R, oldColor.G, oldColor.B));
                }

                var alphaInputBox = GetTemplateChild("AlphaInputBox") as UIElement;
                if (alphaInputBox != null)
                {
                    alphaInputBox.Visibility = newValue == false ? Visibility.Collapsed : Visibility.Visible;
                }

                _internalValueChanging = false;
            }
        }

        public bool UseAlpha
        {
            get { return (bool)GetValue(UseAlphaProperty); }
            set { SetValue(UseAlphaProperty, value); }
        }

        #endregion

        #region ColorStringFormatProperty

        public static readonly DependencyProperty ColorStringFormatProperty = DependencyProperty.Register("ColorStringFormat", typeof(FluentEditorShared.Utils.ColorStringFormat), typeof(ColorEditor), new PropertyMetadata(FluentEditorShared.Utils.ColorStringFormat.PoundRGB, new PropertyChangedCallback(OnColorStringFormatPropertyChanged)));

        private static void OnColorStringFormatPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnColorStringFormatChanged((FluentEditorShared.Utils.ColorStringFormat)e.OldValue, (FluentEditorShared.Utils.ColorStringFormat)e.NewValue);
            }
        }

        private void OnColorStringFormatChanged(FluentEditorShared.Utils.ColorStringFormat oldValue, FluentEditorShared.Utils.ColorStringFormat newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                ValueString = Utils.ColorUtils.FormatColorString(ValueColor, newValue, Precision);

                _internalValueChanging = false;
            }
        }

        public FluentEditorShared.Utils.ColorStringFormat ColorStringFormat
        {
            get { return (FluentEditorShared.Utils.ColorStringFormat)GetValue(ColorStringFormatProperty); }
            set { SetValue(ColorStringFormatProperty, value); }
        }

        #endregion

        #region PrecisionProperty

        public static readonly DependencyProperty PrecisionProperty = DependencyProperty.Register("Precision", typeof(int), typeof(ColorEditor), new PropertyMetadata((int)4, new PropertyChangedCallback(OnPrecisionPropertyChanged)));

        private static void OnPrecisionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnPrecisionChanged((int)e.OldValue, (int)e.NewValue);
            }
        }

        private void OnPrecisionChanged(int oldValue, int newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                ValueString = Utils.ColorUtils.FormatColorString(ValueColor, ColorStringFormat, newValue);

                _internalValueChanging = false;
            }
        }

        public int Precision
        {
            get { return (int)GetValue(PrecisionProperty); }
            set { SetValue(PrecisionProperty, value); }
        }

        #endregion

        #region HeaderProperty

        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(ColorEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnHeaderPropertyChanged)));

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorEditor target)
            {
                target.OnHeaderChanged(e.OldValue, e.NewValue);
            }
        }

        private void OnHeaderChanged(object oldVal, object newVal)
        {
            var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
            if (headerContentPresenter != null)
            {
                headerContentPresenter.Visibility = newVal == null ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        #endregion

        #region HeaderTemplateProperty

        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(ColorEditor), new PropertyMetadata(null));

        public DataTemplate HeaderTemplate
        {
            get { return GetValue(HeaderTemplateProperty) as DataTemplate; }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/ColorPalette/ColorPaletteEntryEditor.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace FluentEditorShared.ColorPalette
{
    public enum ColorPaletteEntryCaptionMode { None, ActiveColorString, Title };

    public class ColorPaletteEntryEditor : Button
    {
        public ColorPaletteEntryEditor()
        {
            this.DefaultStyleKey = typeof(ColorPaletteEntryEditor);

            // Make sure each instance of the control gets its own brush instances
            ActiveColorBrush = new SolidColorBrush();
            ContrastColorBrush = new SolidColorBrush();

            this.Click += ColorPaletteEntryEditor_Click;
        }

        #region ColorPaletteEntryProperty

        public static readonly DependencyProperty ColorPaletteEntryProperty = DependencyProperty.Register("ColorPaletteEntry", typeof(IColorPaletteEntry), typeof(ColorPaletteEntryEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnColorPaletteEntryPropertyChanged)));

        private static void OnColorPaletteEntryPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorPaletteEntryEditor target)
            {
                target.OnColorPaletteEntryChanged(e.OldValue as IColorPaletteEntry, e.NewValue as IColorPaletteEntry);
            }
        }

        private void OnColorPaletteEntryChanged(IColorPaletteEntry oldValue, IColorPaletteEntry newValue)
        {
            if (oldValue != null)
            {
                oldValue.ActiveColorChanged -= ColorPaletteEntry_ActiveColorChanged;
                oldValue.ContrastColorChanged -= ColorPaletteEntry_ContrastColorChanged;
            }

            if (newValue != null)
            {
                ActiveColorBrush.Color = newValue.ActiveColor;
                ContrastColorBrush.Color = newValue.BestContrastColor != null ? newValue.BestContrastColor.Color.ActiveColor : default(Color);
                newValue.ActiveColorChanged += ColorPaletteEntry_ActiveColorChanged;
                newValue.ContrastColorChanged += ColorPaletteEntry_ContrastColorChanged;

                if (_flyoutContent != null)
                {
                    _flyoutContent.Content = newValue;
                }
            }
            else
            {
                HideFlyout();
                ActiveColorBrush.Color = default(Color);
                ContrastColorBrush.Color = default(Color);
            }

            UpdateCaption();
        }

        public IColorPaletteEntry ColorPaletteEntry
        {
            get { return GetValue(ColorPaletteEntryProperty) as IColorPaletteEntry; }
            set { SetValue(ColorPaletteEntryProperty, value); }
        }

        #endregion

        #region CaptionModeProperty

        public static readonly DependencyProperty CaptionModeProperty = DependencyProperty.Register("CaptionMode", typeof(ColorPaletteEntryCaptionMode), typeof(ColorPaletteEntryEditor), new PropertyMetadata(ColorPaletteEntryCaptionMode.ActiveColorString, new PropertyChangedCallback(OnCaptionModePropertyChanged)));

        private static void OnCaptionModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ColorPaletteEntryEditor target)
            {
                target.OnCaptionModeChanged((ColorPaletteEntryCaptionMode)e.OldValue, (ColorPaletteEntryCaptionMode)e.NewValue);
            }
        }

        private void OnCaptionModeChanged(ColorPaletteEntryCaptionMode oldValue, ColorPaletteEntryCaptionMode newValue)
        {
            UpdateCaption();
        }

        public ColorPaletteEntryCaptionMode CaptionMode
        {
            get { return (ColorPaletteEntryCaptionMode)GetValue(CaptionModeProperty); }
            set { SetValue(CaptionModeProperty, value); }
        }

        #endregion

        #region CaptionProperty

        public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(ColorPaletteEntryEditor), new PropertyMetadata(null));

        public string Caption
        {
            get { return GetValue(CaptionProperty) as string; }
            private set { SetValue(CaptionProperty, value); }
        }

        #endregion

        #region FlyoutTemplateProperty

        public static readonly DependencyProperty FlyoutTemplateProperty = DependencyProperty.Register("FlyoutTemplate", typeof(DataTemplate), typeof(ColorPaletteEntryEditor), new PropertyMetadata(null));

        public DataTemplate FlyoutTemplate
        {
            get { return GetValue(FlyoutTemplateProperty) as DataTemplate; }
            set { SetValue(FlyoutTemplateProperty, value); }
        }

        #endregion

        #region FlyoutPresenterStyleProperty

        public static readonly DependencyProperty FlyoutPresenterStyleProperty = DependencyProperty.Register("FlyoutPresenterStyle", typeof(Style), typeof(ColorPaletteEntryEditor), new PropertyMetadata(null));

        public Style FlyoutPresenterStyle
        {
            get { return GetValue(FlyoutPresenterStyleProperty) as Style; }
            set { SetValue(FlyoutPresenterStyleProperty, value); }
        }

        #endregion

        #region ActiveColorBrushProperty

        public static readonly DependencyProperty ActiveColorBrushProperty = DependencyProperty.Register("ActiveColorBrush", typeof(SolidColorBrush), typeof(ColorPaletteEntryEditor), new PropertyMetadata(new SolidColorBrush()));

        public SolidColorBrush ActiveColorBrush
        {
            get { return GetValue(ActiveColorBrushProperty) as SolidColorBrush; }
            private set { SetValue(ActiveColorBrushProperty, value); }
        }

        #endregion

        #region ContrastColorBrushProperty

        public static readonly DependencyProperty ContrastColorBrushProperty = DependencyProperty.Register("ContrastColorBrush", typeof(SolidColorBrush), typeof(ColorPaletteEntryEditor), new PropertyMetadata(new SolidColorBrush()));

        public SolidColorBrush ContrastColorBrush
        {
            get { return GetValue(ContrastColorBrushProperty) as SolidColorBrush; }
            private set { SetValue(ContrastColorBrushProperty, value); }
        }

        #endregion

        private void ColorPaletteEntry_ActiveColorChanged(IColorPaletteEntry obj)
        {
            var paletteEntry = ColorPaletteEntry;
            if (paletteEntry == null)
            {
                return;
            }
            ActiveColorBrush.Color = paletteEntry.ActiveColor;

            UpdateCaption();
        }

        private void ColorPaletteEntry_ContrastColorChanged(IColorPaletteEntry obj)
        {
            var paletteEntry = ColorPaletteEntry;
            if (paletteEntry == null)
            {
                return;
            }
            ContrastColorBrush.Color = paletteEntry.BestContrastColor != null ? paletteEntry.BestContrastColor.Color.ActiveColor : default(Color);
        }

        private void UpdateCaption()
        {
            var captionMode = CaptionMode;
            var paletteEntry = ColorPaletteEntry;
            switch (captionMode)
            {
                case ColorPaletteEntryCaptionMode.None:
                    Caption = string.Empty;
                    break;
                case ColorPaletteEntryCaptionMode.ActiveColorString:
                    Caption = paletteEntry != null ? paletteEntry.ActiveColorString : string.Empty;
                    break;
                case ColorPaletteEntryCaptionMode.Title:
                    Caption = paletteEntry != null ? paletteEntry.Title : string.Empty;
                    break;
            }
        }

        private void ColorPaletteEntryEditor_Click(object sender, RoutedEventArgs e)
        {
            ShowFlyout();
        }

        private Flyout _flyout;
        private ContentControl _flyoutContent;

        private void ShowFlyout()
        {
            HideFlyout();

            var flyoutTemplate = FlyoutTemplate;
            if (flyoutTemplate == null)
            {
                return;
            }

            var paletteEntry = ColorPaletteEntry;

            Flyout flyout = new Flyout();

            var flyoutPresenterStyle = FlyoutPresenterStyle;
            if(flyoutPresenterStyle != null)
            {
                flyout.FlyoutPresenterStyle = flyoutPresenterStyle;
            }

            ContentControl flyoutContent = new ContentControl();
            flyoutContent.ContentTemplate = flyoutTemplate;
            flyoutContent.Content = paletteEntry;
            flyoutContent.HorizontalAlignment = HorizontalAlignment.Stretch;
            flyoutContent.VerticalAlignment = VerticalAlignment.Stretch;
            flyoutContent.Margin = new Thickness(0);
            flyoutContent.Padding = new Thickness(0);

            flyout.Content = flyoutContent;

            flyout.ShowAt(this);
        }

        private void HideFlyout()
        {
            if (_flyout != null)
            {
                _flyout.Hide();
                _flyout = null;
                _flyoutContent = null;
            }
        }
    }
}


<|start_filename|>FluentEditorShared/ObjectPool/IObjectPool.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace FluentEditorShared.ObjectPool
{
    public interface IObjectPool<T> where T : IPoolableObject
    {
        T GetObject();
        void ReturnObject(T target);
    }
}


<|start_filename|>FluentEditorShared/Utils/CubicBezierEasingCache.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.Foundation;

namespace FluentEditorShared.Utils
{
    public class CubicBezierEasingCache
    {
        public CubicBezierEasingCache(Point control1, Point control2)
        {
            _control1 = control1;
            _control2 = control2;

            RebuildCache();
        }

        public CubicBezierEasingCache(double x1, double y1, double x2, double y2)
        {
            _control1 = new Point(x1, y1);
            _control2 = new Point(x2, y2);

            RebuildCache();
        }

        private Point _control1;
        public Point Control1
        {
            get { return _control1; }
            set
            {
                if (_control1 != value)
                {
                    _control1 = value;
                    RebuildCache();
                }
            }
        }

        private Point _control2;
        public Point Control2
        {
            get { return _control2; }
            set
            {
                if (_control2 != value)
                {
                    _control2 = value;
                    RebuildCache();
                }
            }
        }

        public double GetValueImmediate(double x)
        {
            return MathUtils.CubicBezierEasing(x, _control1, _control2);
        }

        public double GetValue(double x)
        {
            if (x < _cacheMin || x > _cacheMax)
            {
                return GetValueImmediate(x);
            }

            int index = (int)Math.Round(((x - _cacheMin) / _cacheWidth) * (double)(_cacheResolution - 1));
            return _cache[index];
        }

        private void RebuildCache()
        {
            _cacheWidth = Math.Abs(_cacheMax - _cacheMin);

            _cache = new double[_cacheResolution];
            for (int i = 0; i < _cacheResolution; i++)
            {
                _cache[i] = GetValueImmediate(((double)i / (double)(_cacheResolution - 1)) * _cacheWidth + _cacheMin);
            }
        }

        private double[] _cache = null;
        private double _cacheWidth = 1;

        private int _cacheResolution = 100;
        public int CacheResolution
        {
            get { return _cacheResolution; }
            set
            {
                if (_cacheResolution != value)
                {
                    _cacheResolution = value;
                    RebuildCache();
                }
            }
        }

        private double _cacheMin = 0;
        public double CacheMin
        {
            get { return _cacheMin; }
            set
            {
                if (_cacheMin != value)
                {
                    _cacheMin = value;
                    RebuildCache();
                }
            }
        }

        private double _cacheMax = 1;
        public double CacheMax
        {
            get { return _cacheMax; }
            set
            {
                if (_cacheMax != value)
                {
                    _cacheMax = value;
                    RebuildCache();
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Utils/PaletteExtraction.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public struct ColorPaletteConstraint
    {
        public static readonly ColorPaletteConstraint DefaultVibrant = new ColorPaletteConstraint("Vibrant", "Vibrant", 0.5, 0.3, 0.7, 1.0, 0.35, 1.0);
        public static readonly ColorPaletteConstraint DefaultLightVibrant = new ColorPaletteConstraint("LightVibrant", "Light Vibrant", 0.74, 0.55, 1.0, 1.0, 0.35, 1.0);
        public static readonly ColorPaletteConstraint DefaultDarkVibrant = new ColorPaletteConstraint("DarkVibrant", "Dark Vibrant", 0.26, 0.0, 0.45, 1.0, 0.35, 1.0);
        public static readonly ColorPaletteConstraint DefaultMuted = new ColorPaletteConstraint("Muted", "Muted", 0.5, 0.3, 0.7, 0.3, 0.0, 0.4);
        public static readonly ColorPaletteConstraint DefaultLightMuted = new ColorPaletteConstraint("LightMuted", "Light Muted", 0.74, 0.55, 1.0, 0.3, 0.0, 0.4);
        public static readonly ColorPaletteConstraint DefaultDarkMuted = new ColorPaletteConstraint("DarkMuted", "Dark Muted", 0.26, 0.0, 0.45, 0.3, 0.0, 0.4);

        //public static readonly Dictionary<string, ColorPaletteConstraint> DefaultPaletteConstraints;
        public static readonly ColorPaletteConstraint[] DefaultPaletteConstraints;

        static ColorPaletteConstraint()
        {
            DefaultPaletteConstraints = new ColorPaletteConstraint[6];
            DefaultPaletteConstraints[0] = DefaultVibrant;
            DefaultPaletteConstraints[1] = DefaultLightVibrant;
            DefaultPaletteConstraints[2] = DefaultDarkVibrant;
            DefaultPaletteConstraints[3] = DefaultMuted;
            DefaultPaletteConstraints[4] = DefaultLightMuted;
            DefaultPaletteConstraints[5] = DefaultDarkMuted;
        }

        public ColorPaletteConstraint(string id, string caption, double targetLuminosity, double minLuminosity, double maxLuminosity, double targetSaturation, double minSaturation, double maxSaturation)
        {
            Id = id;
            Caption = caption;
            TargetLuminosity = targetLuminosity;
            MinLuminosity = minLuminosity;
            MaxLuminosity = maxLuminosity;
            TargetSaturation = targetSaturation;
            MinSaturation = minSaturation;
            MaxSaturation = maxSaturation;
        }

        public readonly string Id;
        public readonly string Caption;
        public readonly double TargetLuminosity;
        public readonly double MinLuminosity;
        public readonly double MaxLuminosity;
        public readonly double TargetSaturation;
        public readonly double MinSaturation;
        public readonly double MaxSaturation;
    }

    public static class PaletteExtraction
    {
        public const double DefaultLuminosityWeight = 3;
        public const double DefaultSaturationWeight = 6;
        public const double DefaultPopulationWeight = 1;

        public static (bool found, Color color, ColorPaletteConstraint constraint)[] ExtractColorPalette(IPixelBlob pixels, ColorPaletteConstraint[] constraints, int quantizedPaletteSize = 64, int pixelSkipping = 5, byte minAlpha = 125, byte maxWhiteLevel = 250, int signifigantBits = 5, int minPopulation = 0, double saturationWeight = DefaultSaturationWeight, double luminosityWeight = DefaultLuminosityWeight, double populationWeight = DefaultPopulationWeight)
        {
            if (constraints == null || constraints.Length == 0)
            {
                return null;
            }

            var quantizedImage = ColorQuantization.Quantize(pixels, quantizedPaletteSize, 0, pixelSkipping, minAlpha, maxWhiteLevel, signifigantBits, minPopulation);
            uint totalPopulation = 0;
            for (int i = 0; i < quantizedImage.Length; i++)
            {
                totalPopulation += quantizedImage[i].population;
            }

            double[] bestFitValues = new double[constraints.Length];
            Color[] colors = new Color[constraints.Length];
            bool[] foundEntry = new bool[constraints.Length];
            for (int i = 0; i < foundEntry.Length; i++)
            {
                foundEntry[i] = false;
                colors[i] = Colors.Black;
                bestFitValues[i] = 0;
            }

            for (int i = quantizedImage.Length - 1; i >= 0; i--)
            {
                // Ignore pixels that are mostly transparent or nearly white
                if (quantizedImage[i].color.A < minAlpha || (quantizedImage[i].color.R >= maxWhiteLevel && quantizedImage[i].color.G >= maxWhiteLevel && quantizedImage[i].color.B >= maxWhiteLevel))
                {
                    continue;
                }

                var pixelColorHSL = ColorUtils.RGBToHSL(quantizedImage[i].color);

                for (int j = 0; j < constraints.Length; j++)
                {
                    if (/* min / max luminosity */ pixelColorHSL.L >= constraints[j].MinLuminosity && pixelColorHSL.L <= constraints[j].MaxLuminosity &&
                        /* min / max saturation */ pixelColorHSL.S >= constraints[j].MinSaturation && pixelColorHSL.S <= constraints[j].MaxSaturation)
                    {
                        double pop = (double)quantizedImage[i].population / (double)totalPopulation;
                        var matchValue = ComputeColorMatchValue(pixelColorHSL, pop, constraints[j].TargetSaturation, constraints[j].TargetLuminosity, saturationWeight, luminosityWeight, populationWeight);
                        if (matchValue > bestFitValues[j])
                        {
                            bool found = false;
                            for (int k = 0; k < j; k++)
                            {
                                if (bestFitValues[k] >= 0 && quantizedImage[i].color == colors[k])
                                {
                                    found = true;
                                    break;
                                }
                            }
                            if (!found)
                            {
                                foundEntry[j] = true;
                                bestFitValues[j] = matchValue;
                                colors[j] = (quantizedImage[i].color);
                            }
                        }
                    }
                }
            }

            (bool found, Color color, ColorPaletteConstraint constraint)[] retVal = new(bool found, Color color, ColorPaletteConstraint constraint)[constraints.Length];
            for (int i = 0; i < constraints.Length; i++)
            {
                retVal[i] = (foundEntry[i], colors[i], constraints[i]);
            }
            return retVal;
        }

        private static double ComputeColorMatchValue(HSL hsl, double population, double targetSaturation, double targetLuminosity, double saturationWeight = DefaultSaturationWeight, double luminosityWeight = DefaultLuminosityWeight, double populationWeight = DefaultPopulationWeight)
        {
            var satVal = 1.0 - Math.Abs(hsl.S - targetSaturation);
            var lumVal = 1.0 - Math.Abs(hsl.L - targetLuminosity);
            return MathUtils.ComputeMean(new double[] { satVal, lumVal, population }, new double[] { saturationWeight, luminosityWeight, populationWeight });
        }

        // This duplicates the bugs in vibrant.js so as to return an identical palette result
        public static (bool found, Color color, ColorPaletteConstraint constraint)[] AlternateExtractColorPalette(IPixelBlob pixels, ColorPaletteConstraint[] constraints)
        {
            if (constraints == null || constraints.Length == 0)
            {
                return null;
            }

            // Duplicate bug in quantize.js which stops the second iteration of quantization too early
            var quantizedImage = ColorQuantization.Quantize(pixels, 64, 1);
            Color[] colors = new Color[constraints.Length];
            bool[] foundEntry = new bool[constraints.Length];
            for (int i = 0; i < foundEntry.Length; i++)
            {
                foundEntry[i] = false;
                colors[i] = Colors.Black;
            }

            // Duplicate the bug in vibrant.js that ignores the color comparison value and just takes the first color that matches the min / max
            for (int j = 0; j < constraints.Length; j++)
            {
                for (int i = quantizedImage.Length - 1; i >= 0; i--)
                {
                    var pixelColorHSL = ColorUtils.RGBToHSL(quantizedImage[i].color);
                    if (/* min / max luminosity */ pixelColorHSL.L >= constraints[j].MinLuminosity && pixelColorHSL.L <= constraints[j].MaxLuminosity &&
                        /* min / max saturation */ pixelColorHSL.S >= constraints[j].MinSaturation && pixelColorHSL.S <= constraints[j].MaxSaturation)
                    {
                        bool found = false;
                        for (int k = 0; k < j; k++)
                        {
                            if (quantizedImage[i].color == colors[k])
                            {
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            foundEntry[j] = true;
                            colors[j] = (quantizedImage[i].color);
                            break;
                        }
                    }
                }
            }

            (bool found, Color color, ColorPaletteConstraint constraint)[] retVal = new(bool found, Color color, ColorPaletteConstraint constraint)[constraints.Length];
            for (int i = 0; i < constraints.Length; i++)
            {
                retVal[i] = (foundEntry[i], colors[i], constraints[i]);
            }
            return retVal;
        }
    }
}


<|start_filename|>FluentEditorShared/ColorPalette/ContrastListItem.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using FluentEditorShared.Utils;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.UI;
using Windows.UI.Xaml.Media;

namespace FluentEditorShared.ColorPalette
{
    public class ContrastListItem : INotifyPropertyChanged
    {
        public ContrastListItem() { }
        public ContrastListItem(IColorPaletteEntry baseColor, IColorPaletteEntry contrastColor, double minContrast = 4.5)
        {
            _minContrast = minContrast;
            _baseColorBrush = new SolidColorBrush();
            _contrastColorBrush = new SolidColorBrush();

            BaseColor = baseColor;
            ContrastColor = contrastColor;
        }

        private void RecalcContrast()
        {
            if (_baseColor == null || _contrastColor == null)
            {
                Contrast = 0.0;
                return;
            }

            Contrast = ColorUtils.ContrastRatio(_baseColor.ActiveColor, _contrastColor.ActiveColor);
        }

        private double _minContrast;
        private double _contrast;
        public double Contrast
        {
            get { return _contrast; }
            private set
            {
                if (_contrast != value)
                {
                    _contrast = value;
                    RaisePropertyChangedFromSource();

                    RaisePropertyChanged("ContrastError");
                }
            }
        }

        public bool ContrastError
        {
            get
            {
                if(_minContrast <= 0)
                {
                    return false;
                }
                return _contrast < _minContrast;
            }
        }

        private IColorPaletteEntry _baseColor;
        public IColorPaletteEntry BaseColor
        {
            get { return _baseColor; }
            set
            {
                if (_baseColor != value)
                {
                    if (_baseColor != null)
                    {
                        _baseColor.ActiveColorChanged -= _baseColor_ActiveColorChanged;
                    }

                    _baseColor = value;
                    RaisePropertyChangedFromSource();

                    if (_baseColor != null)
                    {
                        _baseColorBrush.Color = _baseColor.ActiveColor;
                        _baseColor.ActiveColorChanged += _baseColor_ActiveColorChanged;
                    }

                    RecalcContrast();
                }
            }
        }

        private void _baseColor_ActiveColorChanged(IColorPaletteEntry obj)
        {
            _baseColorBrush.Color = obj.ActiveColor;
            RecalcContrast();
        }

        private SolidColorBrush _baseColorBrush;
        public SolidColorBrush BaseColorBrush
        {
            get { return _baseColorBrush; }
        }

        private IColorPaletteEntry _contrastColor;
        public IColorPaletteEntry ContrastColor
        {
            get { return _contrastColor; }
            set
            {
                if (_contrastColor != value)
                {
                    if (_contrastColor != null)
                    {
                        _contrastColor.ActiveColorChanged -= _contrastColor_ActiveColorChanged;
                    }

                    _contrastColor = value;
                    RaisePropertyChangedFromSource();

                    if (_contrastColor != null)
                    {
                        _contrastColorBrush.Color = _contrastColor.ActiveColor;
                        _contrastColor.ActiveColorChanged += _contrastColor_ActiveColorChanged;
                    }

                    RecalcContrast();
                }
            }
        }

        private void _contrastColor_ActiveColorChanged(IColorPaletteEntry obj)
        {
            _contrastColorBrush.Color = obj.ActiveColor;
            RecalcContrast();
        }

        private SolidColorBrush _contrastColorBrush;
        public SolidColorBrush ContrastColorBrush
        {
            get { return _contrastColorBrush; }
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        private void RaisePropertyChangedFromSource([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}


<|start_filename|>FluentEditor/OuterNav/OuterNavViewModel.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using FluentEditorShared;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace FluentEditor.OuterNav
{
    public class OuterNavViewModel : INotifyPropertyChanged
    {
        public OuterNavViewModel(IReadOnlyList<INavItem> navItems, INavItem selectedNavItem = null)
        {
            if (navItems == null)
            {
                throw new ArgumentNullException("navItems");
            }
            _navItems = new ObservableList<INavItem>(navItems);

            if (selectedNavItem != null)
            {
                if (!_navItems.Contains(selectedNavItem))
                {
                    throw new Exception("selectedNavItem is not contained in navItems");
                }
                _selectedNavItem = selectedNavItem;
            }
        }

        private ObservableList<INavItem> _navItems;
        public ObservableList<INavItem> NavItems
        {
            get { return _navItems; }
        }

        private INavItem _selectedNavItem;
        public INavItem SelectedNavItem
        {
            get { return _selectedNavItem; }
            set
            {
                if (_selectedNavItem != value)
                {
                    _selectedNavItem = value;
                    RaisePropertyChangedFromSource();

                    NavigateToItem?.Invoke(this, _selectedNavItem);
                }
            }
        }

        public event Action<OuterNavViewModel, INavItem> NavigateToItem;

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        private void RaisePropertyChangedFromSource([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/StateTriggers/ElementSizeTrigger.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI.Xaml;

namespace FluentEditorShared.StateTriggers
{
    public enum ElementSizeTriggerAxis { Width, Height };
    public enum ElementSizeTriggerMode { LessThan, GreaterThan, Equals };

    public class ElementSizeTrigger : StateTriggerBase
    {
        private FrameworkElement _targetElement = null;
        public FrameworkElement TargetElement
        {
            get { return _targetElement; }
            set
            {
                if (_targetElement != null)
                {
                    _targetElement.SizeChanged -= _targetElement_SizeChanged;
                }
                _targetElement = value;
                if (_targetElement != null)
                {
                    _targetElement.SizeChanged += _targetElement_SizeChanged;
                }

                EvaluateTrigger();
            }
        }

        private void _targetElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            EvaluateTrigger();
        }

        private ElementSizeTriggerAxis _axis = ElementSizeTriggerAxis.Width;
        public ElementSizeTriggerAxis Axis
        {
            get { return _axis; }
            set
            {
                _axis = value;
                EvaluateTrigger();
            }
        }

        private ElementSizeTriggerMode _mode = ElementSizeTriggerMode.LessThan;
        public ElementSizeTriggerMode Mode
        {
            get { return _mode; }
            set
            {
                _mode = value;
                EvaluateTrigger();
            }
        }

        private double _targetValue = 0.0;
        public double TargetValue
        {
            get { return _targetValue; }
            set
            {
                _targetValue = value;
                EvaluateTrigger();
            }
        }

        private int _targetValuePrecision = 2;
        public int TargetValuePrecision
        {
            get { return _targetValuePrecision; }
            set
            {
                if (value < 0)
                {
                    throw new Exception("TargetValuePrecision must be a nonnegative integer");
                }
                _targetValuePrecision = value;
                EvaluateTrigger();
            }
        }

        private bool _isActive = false;
        public bool IsActive
        {
            get { return _isActive; }
        }

        private void EvaluateTrigger()
        {
            bool newActive = false;

            if (_targetElement != null)
            {
                if (_axis == ElementSizeTriggerAxis.Width)
                {
                    switch (_mode)
                    {
                        case ElementSizeTriggerMode.Equals:
                            newActive = Math.Round(_targetElement.ActualWidth, _targetValuePrecision) == Math.Round(_targetValue, _targetValuePrecision);
                            break;
                        case ElementSizeTriggerMode.GreaterThan:
                            newActive = Math.Round(_targetElement.ActualWidth, _targetValuePrecision) > Math.Round(_targetValue, _targetValuePrecision);
                            break;
                        case ElementSizeTriggerMode.LessThan:
                            newActive = Math.Round(_targetElement.ActualWidth, _targetValuePrecision) < Math.Round(_targetValue, _targetValuePrecision);
                            break;
                    }
                }
                else
                {
                    switch (_mode)
                    {
                        case ElementSizeTriggerMode.Equals:
                            newActive = Math.Round(_targetElement.ActualHeight, _targetValuePrecision) == Math.Round(_targetValue, _targetValuePrecision);
                            break;
                        case ElementSizeTriggerMode.GreaterThan:
                            newActive = Math.Round(_targetElement.ActualHeight, _targetValuePrecision) > Math.Round(_targetValue, _targetValuePrecision);
                            break;
                        case ElementSizeTriggerMode.LessThan:
                            newActive = Math.Round(_targetElement.ActualHeight, _targetValuePrecision) < Math.Round(_targetValue, _targetValuePrecision);
                            break;
                    }
                }
            }

            if (newActive != _isActive)
            {
                _isActive = newActive;
                SetActive(_isActive);
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Editors/EnumEditor.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.Editors
{
    public class EnumEditor : Control
    {
        public EnumEditor()
        {
            this.DefaultStyleKey = typeof(EnumEditor);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var h = Header;
            if (h != null)
            {
                var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
                if (headerContentPresenter != null)
                {
                    headerContentPresenter.Visibility = h == null ? Visibility.Collapsed : Visibility.Visible;
                }
            }
        }

        // Dependency properties can safely be assumed to be single threaded so this is sufficient for dealing with loopbacks on property changed
        private bool _internalValueChanging = false;

        public T GetSelectedValue<T>() where T : struct
        {
            T output;
            if (Enum.TryParse<T>(SelectedString, out output))
            {
                return output;
            }
            return default(T);
        }

        public void SetSelectedValue<T>(T value) where T : struct
        {
            var e = EnumType;
            if (e == null || typeof(T) != EnumType)
            {
                return;
            }
            SelectedString = value.ToString();
        }

        #region EnumTypeProperty

        public static readonly DependencyProperty EnumTypeProperty = DependencyProperty.Register("EnumType", typeof(Type), typeof(EnumEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnEnumTypePropertyChanged)));

        private static void OnEnumTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is EnumEditor target)
            {
                target.OnEnumTypeChanged(e.OldValue as Type, e.NewValue as Type);
            }
        }

        private void OnEnumTypeChanged(Type oldValue, Type newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                if (newValue == null)
                {
                    AvailableStrings = null;
                }
                else
                {
                    try
                    {
                        AvailableStrings = Enum.GetNames(newValue);
                    }
                    catch
                    {
                        AvailableStrings = null;
                    }
                }

                string s = SelectedString;
                if (s != null)
                {
                    var a = AvailableStrings;
                    if (!a.Contains(s))
                    {
                        SelectedString = null;
                        SelectedBoxedEnum = null;
                    }
                }

                _internalValueChanging = false;
            }
        }

        public Type EnumType
        {
            get { return GetValue(EnumTypeProperty) as Type; }
            set { SetValue(EnumTypeProperty, value); }
        }

        #endregion

        #region AvailableStringsProperty

        public static readonly DependencyProperty AvailableStringsProperty = DependencyProperty.Register("AvailableStrings", typeof(string[]), typeof(EnumEditor), new PropertyMetadata(null));

        public string[] AvailableStrings
        {
            get { return GetValue(AvailableStringsProperty) as string[]; }
            set { SetValue(AvailableStringsProperty, value); }
        }
        #endregion

        #region SelectedString

        public static readonly DependencyProperty SelectedStringProperty = DependencyProperty.Register("SelectedString", typeof(string), typeof(EnumEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedStringPropertyChanged)));

        private static void OnSelectedStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is EnumEditor target)
            {
                target.OnSelectedStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnSelectedStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                if (newValue != null)
                {
                    var a = AvailableStrings;
                    if (!a.Contains(newValue))
                    {
                        SelectedString = null;
                        SelectedBoxedEnum = null;
                    }
                    else
                    {
                        SelectedBoxedEnum = Enum.Parse(EnumType, newValue);
                    }
                }
                else
                {
                    SelectedBoxedEnum = null;
                }

                _internalValueChanging = false;
            }
        }

        public string SelectedString
        {
            get { return GetValue(SelectedStringProperty) as string; }
            set { SetValue(SelectedStringProperty, value); }
        }

        #endregion

        #region SelectedBoxedEnumProperty

        public static readonly DependencyProperty SelectedBoxedEnumProperty = DependencyProperty.Register("SelectedBoxedEnum", typeof(object), typeof(EnumEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedBoxedEnumPropertyChanged)));

        private static void OnSelectedBoxedEnumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is EnumEditor target)
            {
                target.OnSelectedBoxedEnumChanged(e.OldValue, e.NewValue);
            }
        }

        private void OnSelectedBoxedEnumChanged(object oldValue, object newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                var t = EnumType;
                if (newValue == null || newValue.GetType() != t)
                {
                    SelectedString = null;
                }
                else
                {
                    SelectedString = newValue.ToString();
                }

                _internalValueChanging = false;
            }
        }

        public object SelectedBoxedEnum
        {
            get { return GetValue(SelectedBoxedEnumProperty); }
            set { SetValue(SelectedBoxedEnumProperty, value); }
        }

        #endregion

        #region HeaderProperty

        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(EnumEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnHeaderPropertyChanged)));

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is EnumEditor target)
            {
                target.OnHeaderChanged(e.OldValue, e.NewValue);
            }
        }

        private void OnHeaderChanged(object oldVal, object newVal)
        {
            var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
            if (headerContentPresenter != null)
            {
                headerContentPresenter.Visibility = newVal == null ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        #endregion

        #region HeaderTemplateProperty

        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(EnumEditor), new PropertyMetadata(null));

        public DataTemplate HeaderTemplate
        {
            get { return GetValue(HeaderTemplateProperty) as DataTemplate; }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/ObjectPool/IPoolableObject.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace FluentEditorShared.ObjectPool
{
    // Implementations of IPoolableObject should not handle their own thread syncronization for IsLive / Reset / Activate state. The owning pool will handle that if any is needed.
    public interface IPoolableObject
    {
        bool IsLive { get; }
        void Reset();
        void Activate();
    }
}


<|start_filename|>FluentEditorShared/StateTriggers/ElementSizeRangeTrigger.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;

namespace FluentEditorShared.StateTriggers
{
    public enum ElementSizeRangeTriggerBound { Closed, Open };

    public class ElementSizeRangeTrigger : StateTriggerBase
    {
        private FrameworkElement _targetElement = null;
        public FrameworkElement TargetElement
        {
            get { return _targetElement; }
            set
            {
                if (_targetElement != null)
                {
                    _targetElement.SizeChanged -= _targetElement_SizeChanged;
                }
                _targetElement = value;
                if (_targetElement != null)
                {
                    _targetElement.SizeChanged += _targetElement_SizeChanged;
                }

                EvaluateTrigger();
            }
        }

        private void _targetElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            EvaluateTrigger();
        }

        private ElementSizeTriggerAxis _axis = ElementSizeTriggerAxis.Width;
        public ElementSizeTriggerAxis Axis
        {
            get { return _axis; }
            set
            {
                _axis = value;
                EvaluateTrigger();
            }
        }

        private ElementSizeRangeTriggerBound _lowerBound = ElementSizeRangeTriggerBound.Closed;
        public ElementSizeRangeTriggerBound LowerBound
        {
            get { return _lowerBound; }
            set
            {
                _lowerBound = value;
                EvaluateTrigger();
            }
        }

        private ElementSizeRangeTriggerBound _upperBound = ElementSizeRangeTriggerBound.Closed;
        public ElementSizeRangeTriggerBound UpperBound
        {
            get { return _upperBound; }
            set
            {
                _upperBound = value;
                EvaluateTrigger();
            }
        }

        private double _lowerValue = 0.0;
        public double LowerValue
        {
            get { return _lowerValue; }
            set
            {
                _lowerValue = value;
                EvaluateTrigger();
            }
        }

        private double _upperValue = 100.0;
        public double UpperValue
        {
            get { return _upperValue; }
            set
            {
                _upperValue = value;
                EvaluateTrigger();
            }
        }

        private bool _isActive = false;
        public bool IsActive
        {
            get { return _isActive; }
        }

        private void EvaluateTrigger()
        {
            if (_lowerValue > _upperValue)
            {
                return;
            }

            bool newActive = true;

            if (_targetElement != null)
            {
                double currentValue = 0.0;
                if (_axis == ElementSizeTriggerAxis.Width)
                {
                    currentValue = _targetElement.ActualWidth;
                }
                else
                {
                    currentValue = _targetElement.ActualHeight;
                }
                if (double.IsNaN(currentValue))
                {
                    return;
                }

                if (_lowerBound == ElementSizeRangeTriggerBound.Closed)
                {
                    if (currentValue < _lowerValue)
                    {
                        newActive = false;
                    }
                }
                else
                {
                    if (currentValue <= _lowerValue)
                    {
                        newActive = false;
                    }
                }
                if (_upperBound == ElementSizeRangeTriggerBound.Closed)
                {
                    if (currentValue > _upperValue)
                    {
                        newActive = false;
                    }
                }
                else
                {
                    if (currentValue >= _upperValue)
                    {
                        newActive = false;
                    }
                }
            }

            if (newActive != _isActive)
            {
                _isActive = newActive;
                SetActive(_isActive);
            }
        }
    }
}


<|start_filename|>FluentEditorShared/ObjectPool/PoolableWrapper.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace FluentEditorShared.ObjectPool
{
    // Wrapper for making object pools of types which do not themselves implement IPoolableObject
    // This is not thread safe and assumes the object pool will handle any synchronization
    public class PoolableWrapper<T> : IPoolableObject
    {
        public PoolableWrapper(T payload, Action<T> resetHandler = null, Action<T> activationHandler = null)
        {
            _payload = payload;
            _resetHandler = resetHandler;
            _activationHandler = activationHandler;
        }

        private bool _isLive = false;
        public bool IsLive
        {
            get { return _isLive; }
        }

        private readonly Action<T> _resetHandler = null;
        public void Reset()
        {
            if(_resetHandler != null)
            {
                _resetHandler(_payload);
            }
            _isLive = false;
        }

        private readonly Action<T> _activationHandler = null;
        public void Activate()
        {
            if(_activationHandler != null)
            {
                _activationHandler(_payload);
            }
            _isLive = true;
        }

        private readonly T _payload = default;
        public T Payload
        {
            get { return _payload; }
        }
    }
}


<|start_filename|>FluentEditor/OuterNav/INavItem.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ComponentModel;

namespace FluentEditor.OuterNav
{
    public interface INavItem : INotifyPropertyChanged
    {
        string Id { get; }
        string Title { get; }
        string Glyph { get; }
    }
}


<|start_filename|>FluentEditorShared/MessageBus/MessageBus.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;

namespace FluentEditorShared.MessageBus
{
    public class MessageBus : IMessageBus, IReadOnlyMessageBus
    {
        #region Listener wrappers

        private interface ISubscriberAdapter
        {
            bool NeedsPruning();
            bool Lock();
            void Unlock();
            bool Broadcast<T>(in T message, bool unlock = true) where T : struct;
            bool CompareTarget(object target);
            ISubscriberAdapter Clone();
        }

        // Not thread safe, relies on the messagebus itself for synchronization
        private class ListenerAdapter : ISubscriberAdapter
        {
            public ListenerAdapter(WeakReference<IMessageBusListener> listener)
            {
                _listener = listener;
            }

            private readonly WeakReference<IMessageBusListener> _listener = null;
            private IMessageBusListener _liveRef = null;

            public bool Lock()
            {
                if (_liveRef != null)
                {
                    return true;
                }
                return _listener.TryGetTarget(out _liveRef);
            }

            public void Unlock()
            {
                _liveRef = null;
            }

            public bool NeedsPruning()
            {
                var retVal = !Lock();
                Unlock();
                return retVal;
            }

            public bool Broadcast<T>(in T message, bool unlock = true) where T : struct
            {
                if (_liveRef == null)
                {
                    if (!Lock())
                    {
                        return false;
                    }
                }

                _liveRef.OnMessage<T>(message);
                if (unlock)
                {
                    Unlock();
                }
                return true;
            }

            public bool CompareTarget(object target)
            {
                if (target == null)
                {
                    return false;
                }
                if (_liveRef != null)
                {
                    return _liveRef == target;
                }
                IMessageBusListener liveRef = null;
                if (!_listener.TryGetTarget(out liveRef))
                {
                    return false;
                }
                return liveRef == target;
            }

            public ISubscriberAdapter Clone()
            {
                var retVal = new ListenerAdapter(_listener);
                retVal._liveRef = _liveRef;
                return retVal;
            }
        }

        // Not thread safe, relies on the messagebus itself for synchronization
        private class DelegateAdapter<T> : ISubscriberAdapter where T : struct
        {
            public DelegateAdapter(Action<T> targetDelegate)
            {
                if (targetDelegate == null)
                {
                    throw new ArgumentNullException("targetDelegate");
                }
                _delegate = targetDelegate;
            }

            private readonly Action<T> _delegate;

            public bool Lock() { return true; }

            public void Unlock() { /* Deliberately empty */ }

            public bool NeedsPruning() { return false; }

            public bool Broadcast<U>(in U message, bool unlock = true) where U : struct
            {
                if (_delegate is Action<U> d)
                {
                    d(message);
                    return true;
                }
                return false;
            }

            public bool CompareTarget(object target)
            {
                if (target == null || _delegate == null)
                {
                    return false;
                }
                return target.Equals(_delegate);
            }

            public ISubscriberAdapter Clone()
            {
                return new DelegateAdapter<T>(_delegate);
            }
        }

        #endregion

        public MessageBus() { }

        private object _lock = new object();
        private Dictionary<Type, List<ISubscriberAdapter>> _subscriptions = new Dictionary<Type, List<ISubscriberAdapter>>();

        public void AddListener<T>(IMessageBusListener listener) where T : struct
        {
            lock (_lock)
            {
                var messageType = typeof(T);
                if (!_subscriptions.ContainsKey(messageType))
                {
                    var subList = new List<ISubscriberAdapter>(1);
                    subList.Add(new ListenerAdapter(new WeakReference<IMessageBusListener>(listener)));
                    _subscriptions.Add(messageType, subList);
                }
                else
                {
                    var subList = _subscriptions[typeof(T)];
                    if (null == subList.FirstOrDefault((a) => a.CompareTarget(listener)))
                    {
                        subList.Add(new ListenerAdapter(new WeakReference<IMessageBusListener>(listener)));
                    }
                }
            }
        }

        public void AddListener<T>(Action<T> d) where T : struct
        {
            lock (_lock)
            {
                var messageType = typeof(T);
                if (!_subscriptions.ContainsKey(messageType))
                {
                    var subList = new List<ISubscriberAdapter>(1);
                    subList.Add(new DelegateAdapter<T>(d));
                    _subscriptions.Add(messageType, subList);
                }
                else
                {
                    var subList = _subscriptions[typeof(T)];
                    if (null == subList.FirstOrDefault((a) => a.CompareTarget(d)))
                    {
                        subList.Add(new DelegateAdapter<T>(d));
                    }
                }
            }
        }

        public void RemoveListener<T>(IMessageBusListener listener) where T : struct
        {
            lock (_lock)
            {
                var messageType = typeof(T);
                if (_subscriptions.ContainsKey(messageType))
                {
                    var subList = _subscriptions[messageType];
                    subList.RemoveAll((a) => a.CompareTarget(listener));
                }
            }
        }

        public void RemoveListener<T>(Action<T> d) where T : struct
        {
            lock (_lock)
            {
                var messageType = typeof(T);
                if (_subscriptions.ContainsKey(messageType))
                {
                    var subList = _subscriptions[messageType];
                    subList.RemoveAll((a) => a.CompareTarget(d));
                }
            }
        }

        // Currently this generates some garbage per broadcast in the form of an array holding the recipients of the message (needs to make a copy of the listener list in case listeners Remove themselves in response to the message)
        // this could be mitigated at the cost of some complexity if it becomes a problem
        public void BroadcastMessage<T>(in T message) where T : struct
        {
            List<ISubscriberAdapter> broadcastList = null;

            lock (_lock)
            {
                var messageType = typeof(T);
                if (!_subscriptions.ContainsKey(messageType))
                {
                    return;
                }
                var subList = _subscriptions[messageType];
                if (subList.Count == 0)
                {
                    return;
                }
                broadcastList = new List<ISubscriberAdapter>(subList.Count);
                foreach (var sub in subList)
                {
                    if (sub.Lock())
                    {
                        broadcastList.Add(sub.Clone());
                    }
                    sub.Unlock();
                }
            }

            if (broadcastList.Count > 0)
            {
                foreach (var subscriber in broadcastList)
                {
                    subscriber.Broadcast(in message, true);
                }
            }
        }

        public void PruneListeners()
        {
            lock (_lock)
            {
                foreach (var type in _subscriptions.Keys)
                {
                    var subList = _subscriptions[type];
                    subList.RemoveAll((a) => a.NeedsPruning());
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Utils/ColorQuantization.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public enum RGBAxis { Red, Green, Blue };

    public class ColorQuantizationBox
    {
        public ColorQuantizationBox(IPixelBlob pixels, int signifigantBits = 5, int pixelSkipping = 5, byte minAlpha = 125, byte whiteCutoff = 250)
        {
            if (pixels == null)
            {
                throw new ArgumentNullException("pixels");
            }
            if (signifigantBits <= 0 || signifigantBits > 8)
            {
                throw new ArgumentException("signifigantBits must be in the range [1,8]");
            }
            SignifigantBits = signifigantBits;
            int sigShift = 8 - SignifigantBits;
            int retLength = 1 << (3 * SignifigantBits);
            Histogram = new uint[retLength];
            int pixelCount = 0;

            MinRed = 255;
            MaxRed = 0;
            MinGreen = 255;
            MaxGreen = 0;
            MinBlue = 255;
            MaxBlue = 0;

            for (uint y = 0; y < pixels.Height; y++)
            {
                for (uint x = 0; x < pixels.Width; x++)
                {
                    if (pixelCount++ % pixelSkipping != 0)
                    {
                        continue;
                    }
                    var c = pixels.GetPixel(x, y);
                    if (c.A < minAlpha || (c.R > whiteCutoff && c.G > whiteCutoff && c.B > whiteCutoff))
                    {
                        continue;
                    }
                    byte r = (byte)(c.R >> sigShift);
                    byte g = (byte)(c.G >> sigShift);
                    byte b = (byte)(c.B >> sigShift);
                    int index = GetColorIndex(r, g, b, SignifigantBits);
                    Histogram[index] += 1;

                    MinRed = Math.Min(MinRed, r);
                    MaxRed = Math.Max(MaxRed, r);
                    MinGreen = Math.Min(MinGreen, g);
                    MaxGreen = Math.Max(MaxGreen, g);
                    MinBlue = Math.Min(MinBlue, b);
                    MaxBlue = Math.Max(MaxBlue, b);
                }
            }

            HistogramTotal = 0;
            for (int i = MinRed; i <= MaxRed; i++)
            {
                for (int j = MinGreen; j <= MaxGreen; j++)
                {
                    for (int k = MinBlue; k <= MaxBlue; k++)
                    {
                        var index = GetColorIndex((byte)i, (byte)j, (byte)k, SignifigantBits);
                        HistogramTotal += Histogram[index];
                    }
                }
            }
        }

        public ColorQuantizationBox(ColorQuantizationBox source)
        {
            SignifigantBits = source.SignifigantBits;
            Histogram = source.Histogram;
            HistogramTotal = source.HistogramTotal;
            MinRed = source.MinRed;
            MaxRed = source.MaxRed;
            MinGreen = source.MinGreen;
            MaxGreen = source.MaxGreen;
            MinBlue = source.MinBlue;
            MaxBlue = source.MaxBlue;
        }

        public ColorQuantizationBox(uint[] histogram, byte minRed, byte maxRed, byte minGreen, byte maxGreen, byte minBlue, byte maxBlue, int signifigantBits = 5, int minPopulation = 0)
        {
            if (histogram == null)
            {
                throw new ArgumentNullException("histogram");
            }
            if (signifigantBits <= 0 || signifigantBits > 8)
            {
                throw new ArgumentException("signifigantBits must be in the range [1,8]");
            }
            SignifigantBits = signifigantBits;
            int sigShift = 8 - SignifigantBits;
            Histogram = histogram;
            MinRed = minRed;
            MaxRed = maxRed;
            MinGreen = minGreen;
            MaxGreen = maxGreen;
            MinBlue = minBlue;
            MaxBlue = maxBlue;

            HistogramTotal = 0;
            for (int i = MinRed; i <= MaxRed; i++)
            {
                for (int j = MinGreen; j <= MaxGreen; j++)
                {
                    for (int k = MinBlue; k <= MaxBlue; k++)
                    {
                        var index = GetColorIndex((byte)i, (byte)j, (byte)k, SignifigantBits);
                        HistogramTotal += Histogram[index];
                    }
                }
            }
        }

        private static int GetColorIndex(byte r, byte g, byte b, int signifigantBits = 5)
        {
            return (r << (2 * signifigantBits)) + (g << signifigantBits) + b;
        }

        public Color ComputeAverageColor()
        {
            int multiplier = 1 << (8 - SignifigantBits);
            double total = (double)HistogramTotal;
            double redTotal = 0;
            double greenTotal = 0;
            double blueTotal = 0;
            for (int i = MinRed; i <= MaxRed; i++)
            {
                for (int j = MinGreen; j <= MaxGreen; j++)
                {
                    for (int k = MinBlue; k <= MaxBlue; k++)
                    {
                        var index = GetColorIndex((byte)i, (byte)j, (byte)k, SignifigantBits);
                        double h = (double)Histogram[index];
                        redTotal += h * ((double)i + 0.5) * multiplier;
                        greenTotal += h * ((double)j + 0.5) * multiplier;
                        blueTotal += h * ((double)k + 0.5) * multiplier;
                    }
                }
            }
            if (total > 0)
            {
                double red = Math.Round(redTotal / total);
                double green = Math.Round(greenTotal / total);
                double blue = Math.Round(blueTotal / total);
                return Color.FromArgb(255, (byte)red, (byte)green, (byte)blue);
            }
            else
            {
                double red = Math.Round(multiplier * (double)(MinRed + MaxRed + 1) / 2.0);
                double green = Math.Round(multiplier * (double)(MinGreen + MaxGreen + 1) / 2.0);
                double blue = Math.Round(multiplier * (double)(MinBlue + MaxBlue + 1) / 2.0);
                return Color.FromArgb(255, (byte)red, (byte)green, (byte)blue);
            }
        }

        public Tuple<ColorQuantizationBox, ColorQuantizationBox> MedianCut()
        {
            if (this.HistogramTotal <= 1)
            {
                return new Tuple<ColorQuantizationBox, ColorQuantizationBox>(this, null);
            }

            uint total = 0;
            uint[] partialSum = null;
            RGBAxis primaryAxis = WidestAxis;
            byte primaryMin, primaryMax;

            if (primaryAxis == RGBAxis.Red)
            {
                primaryMin = MinRed;
                primaryMax = MaxRed;
                partialSum = new uint[RedRange + 1];
                for (byte i = MinRed; i <= MaxRed; i++)
                {
                    uint sum = 0;
                    for (byte j = MinGreen; j <= MaxGreen; j++)
                    {
                        for (byte k = MinBlue; k <= MaxBlue; k++)
                        {
                            var index = GetColorIndex(i, j, k, SignifigantBits);
                            sum += Histogram[index];
                        }
                    }
                    total += sum;
                    partialSum[i - primaryMin] = total;
                }
            }
            else if (primaryAxis == RGBAxis.Green)
            {
                primaryMin = MinGreen;
                primaryMax = MaxGreen;
                partialSum = new uint[GreenRange + 1];
                for (byte i = MinGreen; i <= MaxGreen; i++)
                {
                    uint sum = 0;
                    for (byte j = MinRed; j <= MaxRed; j++)
                    {
                        for (byte k = MinBlue; k <= MaxBlue; k++)
                        {
                            var index = GetColorIndex(j, i, k, SignifigantBits);
                            sum += Histogram[index];
                        }
                    }
                    total += sum;
                    partialSum[i - primaryMin] = total;
                }
            }
            else
            {
                primaryMin = MinBlue;
                primaryMax = MaxBlue;
                partialSum = new uint[BlueRange + 1];
                for (byte i = MinBlue; i <= MaxBlue; i++)
                {
                    uint sum = 0;
                    for (byte j = MinRed; j <= MaxRed; j++)
                    {
                        for (byte k = MinGreen; k <= MaxGreen; k++)
                        {
                            var index = GetColorIndex(j, k, i, SignifigantBits);
                            sum += Histogram[index];
                        }
                    }
                    total += sum;
                    partialSum[i - primaryMin] = total;
                }
            }

            if (primaryMin == primaryMax)
            {
                return new Tuple<ColorQuantizationBox, ColorQuantizationBox>(this, null);
            }

            uint[] lookAheadSum = new uint[partialSum.Length];
            for (int i = 0; i < partialSum.Length; i++)
            {
                lookAheadSum[i] = total - partialSum[i];
            }

            for (byte i = primaryMin; i <= primaryMax; i++)
            {
                var partial = partialSum[i - primaryMin];
                if (partial > total / 2)
                {
                    float left = i - primaryMin;
                    float right = primaryMax - i;
                    int cutValue = 0;
                    if (left <= right)
                    {
                        cutValue = Math.Min(primaryMax - 1, (int)Math.Floor((float)i + right / 2f));
                    }
                    else
                    {
                        cutValue = Math.Max(primaryMin, (int)Math.Floor((float)i - 1f - left / 2f));
                    }
                    while (partialSum[cutValue - primaryMin] <= 0)
                    {
                        cutValue++;
                    }
                    if (cutValue - primaryMin >= partialSum.Length)
                    {
                        cutValue = partialSum.Length - 1 + primaryMin;
                    }
                    uint lookAhead = lookAheadSum[cutValue - primaryMin];
                    while (lookAhead == 0 && cutValue > primaryMin && partialSum[cutValue - primaryMin - 1] != 0)
                    {
                        cutValue--;
                        lookAhead = lookAheadSum[cutValue - primaryMin];
                    }

                    ColorQuantizationBox leftBox = null, rightBox = null;
                    if (primaryAxis == RGBAxis.Red)
                    {
                        leftBox = new ColorQuantizationBox(Histogram, MinRed, (byte)(cutValue), MinGreen, MaxGreen, MinBlue, MaxBlue, SignifigantBits);
                        rightBox = new ColorQuantizationBox(Histogram, (byte)(cutValue + 1), MaxRed, MinGreen, MaxGreen, MinBlue, MaxBlue, SignifigantBits);
                    }
                    else if (primaryAxis == RGBAxis.Green)
                    {
                        leftBox = new ColorQuantizationBox(Histogram, MinRed, MaxRed, MinGreen, (byte)(cutValue), MinBlue, MaxBlue, SignifigantBits);
                        rightBox = new ColorQuantizationBox(Histogram, MinRed, MaxRed, (byte)(cutValue + 1), MaxGreen, MinBlue, MaxBlue, SignifigantBits);
                    }
                    else
                    {
                        leftBox = new ColorQuantizationBox(Histogram, MinRed, MaxRed, MinGreen, MaxGreen, MinBlue, (byte)(cutValue), SignifigantBits);
                        rightBox = new ColorQuantizationBox(Histogram, MinRed, MaxRed, MinGreen, MaxGreen, (byte)(cutValue + 1), MaxBlue, SignifigantBits);
                    }


                    return new Tuple<ColorQuantizationBox, ColorQuantizationBox>(leftBox, rightBox);
                }
            }

            throw new Exception("Unable to find median partial sum. This should never happen");
        }

        public readonly int SignifigantBits;
        public readonly uint[] Histogram;
        public readonly uint HistogramTotal;

        public readonly byte MinRed;
        public readonly byte MaxRed;
        public int RedRange
        {
            get { return MaxRed - MinRed; }
        }

        public readonly byte MinGreen;
        public readonly byte MaxGreen;
        public int GreenRange
        {
            get { return MaxGreen - MinGreen; }
        }

        public readonly byte MinBlue;
        public readonly byte MaxBlue;
        public int BlueRange
        {
            get { return MaxBlue - MinBlue; }
        }

        public RGBAxis WidestAxis
        {
            get
            {
                var r = RedRange;
                var g = GreenRange;
                var b = BlueRange;
                if (r >= g && r >= b)
                {
                    return RGBAxis.Red;
                }
                if (g >= r && g >= b)
                {
                    return RGBAxis.Green;
                }
                else
                {
                    return RGBAxis.Blue;
                }
            }
        }

        public int ColorVolume
        {
            get { return (RedRange + 1) * (GreenRange + 1) * (BlueRange + 1); }
        }

        public static void InsertIntoSortedList(List<ColorQuantizationBox> list, ColorQuantizationBox newItem, Func<ColorQuantizationBox, long> sortPriority)
        {
            if (list.Count == 0)
            {
                list.Add(newItem);
                return;
            }
            long newItemPriority = sortPriority(newItem);
            if (newItemPriority < sortPriority(list[0]))
            {
                list.Insert(0, newItem);
                return;
            }
            if (newItemPriority > sortPriority(list.Last()))
            {
                list.Add(newItem);
                return;
            }

            int newIndex = 0;
            for (int i = 0; i < list.Count; i++)
            {
                if (newItemPriority <= sortPriority(list[i]))
                {
                    newIndex = i;
                    break;
                }
            }
            list.Insert(newIndex, newItem);
        }
    }

    // Based on Modified Median Cut Quantization from https://github.com/DanBloomberg/leptonica/blob/master/src/colorquant2.c
    public static class ColorQuantization
    {
        private static int CountValidColors(List<ColorQuantizationBox> queue, int minPopulation)
        {
            int retVal = 0;
            if (queue == null)
            {
                return retVal;
            }
            for (int i = 0; i < queue.Count; i++)
            {
                if (queue[i].HistogramTotal >= minPopulation)
                {
                    retVal++;
                }
            }
            return retVal;
        }

        public static (uint population, Color color)[] Quantize(IPixelBlob pixels, int finalPaletteMax = 64, int finalPaletteOffset = 0, int pixelSkipping = 5, byte minAlpha = 125, byte maxWhiteLevel = 250, int signifigantBits = 5, int minPopulation = 0, float fractionByPopulation = 0.75f, int maxIterations = 1000)
        {
            if (pixels == null || pixels.TotalPixels <= finalPaletteMax)
            {
                throw new ArgumentException("Invalid pixels");
            }
            if (finalPaletteMax <= 0 || finalPaletteMax > 256)
            {
                throw new ArgumentException("FinalPaletteSize must be in the range [0,256]");
            }
            if (signifigantBits <= 0 || signifigantBits > 8)
            {
                throw new ArgumentException("SignifigantBits must be in the range [1,8]");
            }
            int sigShift = 8 - signifigantBits;

            var initialVBox = new ColorQuantizationBox(pixels, signifigantBits, pixelSkipping, minAlpha, maxWhiteLevel);

            if (initialVBox.Histogram.Length <= finalPaletteMax)
            {
                Color[] smallRet = new Color[initialVBox.ColorVolume];
                int index = 0;
                for (int r = initialVBox.MinRed; r <= initialVBox.MaxRed; r++)
                {
                    for (int g = initialVBox.MinGreen; g <= initialVBox.MaxGreen; g++)
                    {
                        for (int b = initialVBox.MinBlue; b <= initialVBox.MaxBlue; b++)
                        {
                            // TODO test this
                            byte red = (byte)(r << sigShift);
                            byte green = (byte)(g << sigShift);
                            byte blue = (byte)(b << sigShift);
                            index++;
                        }
                    }
                }
            }

            List<ColorQuantizationBox> queue = new List<ColorQuantizationBox>(finalPaletteMax);
            queue.Add(initialVBox);

            int targetColors = (int)(fractionByPopulation * (float)finalPaletteMax);
            int iterationCount = 0;
            while (iterationCount <= maxIterations)
            {
                ColorQuantizationBox vbox = queue.Last();
                queue.RemoveAt(queue.Count - 1);

                var cutBoxes = vbox.MedianCut();
                ColorQuantizationBox.InsertIntoSortedList(queue, cutBoxes.Item1, (item) => item.HistogramTotal);
                if (cutBoxes.Item2 != null)
                {
                    ColorQuantizationBox.InsertIntoSortedList(queue, cutBoxes.Item2, (item) => item.HistogramTotal);
                }

                if (CountValidColors(queue, minPopulation) >= targetColors)
                {
                    break;
                }

                iterationCount++;
            }

            queue.Sort((a, b) => (a.HistogramTotal * a.ColorVolume).CompareTo(b.HistogramTotal * b.ColorVolume));

            iterationCount = 0;
            // There is a bug in vibrant.js that stops its loop one early here. Keeping the bug so as to make the final palettes match.
            targetColors = finalPaletteMax - finalPaletteOffset;
            while (iterationCount <= maxIterations)
            {
                ColorQuantizationBox vbox = queue.Last();
                queue.RemoveAt(queue.Count - 1);

                var cutBoxes = vbox.MedianCut();
                ColorQuantizationBox.InsertIntoSortedList(queue, cutBoxes.Item1, (item) => item.HistogramTotal * item.ColorVolume);
                if (cutBoxes.Item2 != null)
                {
                    ColorQuantizationBox.InsertIntoSortedList(queue, cutBoxes.Item2, (item) => item.HistogramTotal * item.ColorVolume);
                }
                if (CountValidColors(queue, minPopulation) >= targetColors)
                {
                    break;
                }

                iterationCount++;
            }

            int returnCount = CountValidColors(queue, minPopulation);
            int returnIndex = 0;
            (uint population, Color color)[] retVal = new (uint population, Color color)[returnCount];
            for (int i = 0; i < queue.Count; i++)
            {
                if (queue[i].HistogramTotal >= minPopulation)
                {
                    retVal[returnIndex] = (queue[i].HistogramTotal, queue[i].ComputeAverageColor());
                    returnIndex++;
                }
            }
            return retVal;
        }
    }
}


<|start_filename|>FluentEditorShared/ViewCommon/ViewContainer.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.ViewCommon
{
    public class ViewContainer : Control
    {
        public ViewContainer()
        {
            this.DefaultStyleKey = typeof(ViewContainer);
        }

        private Border _outerContainer = null;

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _outerContainer = GetTemplateChild("OuterContainer") as Border;

            if (ViewModel != null)
            {
                BuildView();
            }
        }

        private void BuildView()
        {
            var factory = ViewFactory;
            if (factory != null)
            {
                IView view = factory(ViewModel);
                if (view != null)
                {
                    view.ViewFactory = ViewFactory;
                    view.AttachViewModel(ViewModel);
                }
                _outerContainer.Child = view as UIElement;
            }
        }        

        #region ViewFactory property

        public static readonly DependencyProperty ViewFactoryProperty = DependencyProperty.Register("ViewFactory", typeof(ViewFactoryDelegate), typeof(ViewContainer), null);

        public ViewFactoryDelegate ViewFactory
        {
            get { return GetValue(ViewFactoryProperty) as ViewFactoryDelegate; }
            set { SetValue(ViewFactoryProperty, value); }
        }

        #endregion

        #region ViewModel property

        public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof(object), typeof(ViewContainer), new PropertyMetadata(null, new PropertyChangedCallback(OnViewModelPropertyChanged)));

        private static void OnViewModelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if(d is ViewContainer source)
            {
                source.OnViewModelChanged(d, e);
            }
        }

        private void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // _outerContainer == null is a legit case between the ctor completing and the template finishing load
            if (_outerContainer != null)
            {
                if (_outerContainer.Child != null)
                {
                    var oldView = _outerContainer.Child as IView;
                    if (oldView != null)
                    {
                        oldView.DetachViewModel();
                        oldView.ViewFactory = null;
                    }

                    _outerContainer.Child = null;
                }

                BuildView();
            }
        }

        public object ViewModel
        {
            get { return GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }
        }

        #endregion

    }
}


<|start_filename|>FluentEditor/ControlPalette/ExportView.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI.Xaml.Controls;

namespace FluentEditor.ControlPalette.Export
{
    public sealed partial class ExportView : Page
    {
        public ExportView(ExportViewModel viewModel)
        {
            if (viewModel == null)
            {
                throw new ArgumentNullException("viewModel");
            }
            _viewModel = viewModel;
            this.InitializeComponent();
        }

        private readonly ExportViewModel _viewModel;
        public ExportViewModel ViewModel { get { return _viewModel; } }
    }
}


<|start_filename|>FluentEditor/ControlPalette/ExportViewModel.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Xaml;

namespace FluentEditor.ControlPalette.Export
{
    public class ExportViewModel : INotifyPropertyChanged
    {
        public ExportViewModel()
            : this(null) { }

        public ExportViewModel(string exportText)
        {
            _exportText = exportText;
        }

        private string _exportText;
        public string ExportText
        {
            get { return _exportText; }
            set
            {
                if(_exportText != value)
                {
                    _exportText = value;
                    RaisePropertyChangedFromSource();
                    RaisePropertyChanged("ReadyToCopy");
                }
            }
        }

        public bool ReadyToCopy
        {
            get
            {
                return !string.IsNullOrEmpty(_exportText);
            }
        }

        public void OnCopyToClipboard(object sender, RoutedEventArgs e)
        {
            DataPackage data = new DataPackage();
            data.RequestedOperation = DataPackageOperation.Copy;
            data.SetText(_exportText);
            Clipboard.SetContent(data);
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        private void RaisePropertyChangedFromSource([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/ViewCommon/ViewBase.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.ViewCommon
{
    public abstract class ViewBase<T> : UserControl, IView where T : class
    {
        // The viewmodel can be attached via the weakly typed AttachViewModel but still want to have a strongly typed dependency property to x:Bind to
        public void AttachViewModel(object viewModel)
        {
            ViewModel = viewModel as T;
        }

        public void DetachViewModel()
        {
            ViewModel = null;
        }

        #region ViewModel property

        // The viewmodel can be attached via the weakly typed AttachViewModel but still want to have a strongly typed dependency property to x:Bind to
        public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof(T), typeof(ViewBase<T>), new PropertyMetadata(null, new PropertyChangedCallback(OnViewModelPropertyChanged)));

        public T ViewModel
        {
            get { return GetValue(ViewModelProperty) as T; }
            set { SetValue(ViewModelProperty, value); }
        }

        private static void OnViewModelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ViewBase<T> target)
            {
                target.OnViewModelChanged(e.OldValue as T, e.NewValue as T);
            }
        }

        protected virtual void OnViewModelChanged(T oldViewModel, T newViewModel)
        {
            // derived classes might need to do something here
        }

        #endregion

        #region ViewFactory property

        public static readonly DependencyProperty ViewFactoryProperty = DependencyProperty.Register("ViewFactory", typeof(ViewFactoryDelegate), typeof(ViewBase<T>), new PropertyMetadata(null, new PropertyChangedCallback(OnViewFactoryPropertyChanged)));

        public ViewFactoryDelegate ViewFactory
        {
            get { return GetValue(ViewFactoryProperty) as ViewFactoryDelegate; }
            set { SetValue(ViewFactoryProperty, value); }
        }

        private static void OnViewFactoryPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ViewBase<T> target)
            {
                target.OnViewFactoryChanged(e.OldValue as ViewFactoryDelegate, e.NewValue as ViewFactoryDelegate);
            }
        }

        protected virtual void OnViewFactoryChanged(ViewFactoryDelegate oldViewFactory, ViewFactoryDelegate newViewFactory)
        {
            // derived classes might need to do something here
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/DependencyContainer/IDependencyContainer.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace FluentEditorShared.DependencyContainer
{
    // It is common for a dependency container to use Type as its key. In this case we want to be able to have multiple dependencies of the same type so an explicit Id is needed.
    // This implementation also does not allow for removal of dependencies once added. That is not a needed feature at this time and would require that users of such a container subscribe to events and handle cases of their dependencies being removed at runtime.
    public interface IDependencyContainer
    {
        void AddDependency<T>(string id, T dependency) where T : class;
        T GetDependency<T>(string id) where T : class;
    }
}


<|start_filename|>FluentEditorShared/Editors/DoubleEditor.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.Editors
{
    public class DoubleEditor : Control
    {
        public DoubleEditor()
        {
            this.DefaultStyleKey = typeof(DoubleEditor);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var h = Header;
            if (h != null)
            {
                var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
                if (headerContentPresenter != null)
                {
                    headerContentPresenter.Visibility = h == null ? Visibility.Collapsed : Visibility.Visible;
                }
            }
        }

        // Dependency properties can safely be assumed to be single threaded so this is sufficient for dealing with loopbacks on property changed
        private bool _internalValueChanging = false;

        private double AdjustValue(double i)
        {
            int p = Precision;
            if (p > 0)
            {
                i = Math.Round(i, p);
            }
            double min = MinValue;
            double max = MaxValue;
            if (i < min)
            {
                i = min;
            }
            if (i > max)
            {
                i = max;
            }

            return i;
        }

        #region ValueProperty

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(DoubleEditor), new PropertyMetadata(0.0, new PropertyChangedCallback(OnValuePropertyChanged)));

        private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DoubleEditor target)
            {
                target.OnValueChanged((double)e.OldValue, (double)e.NewValue);
            }
        }

        private void OnValueChanged(double oldValue, double newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                newValue = AdjustValue(newValue);
                Value = newValue;
                ValueString = newValue.ToString();
                ValueInt = (int)Math.Round(newValue);

                _internalValueChanging = false;
            }
        }

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        #endregion

        #region ValueStringProperty

        public static readonly DependencyProperty ValueStringProperty = DependencyProperty.Register("ValueString", typeof(string), typeof(DoubleEditor), new PropertyMetadata("0", new PropertyChangedCallback(OnValueStringPropertyChanged)));

        private static void OnValueStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DoubleEditor target)
            {
                target.OnValueStringChanged(e.OldValue as string, e.NewValue as string);
            }
        }

        private void OnValueStringChanged(string oldValue, string newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                if (string.IsNullOrEmpty(newValue))
                {
                    return;
                }
                double newVal;
                if (!double.TryParse(newValue, out newVal))
                {
                    return;
                }
                newVal = AdjustValue(newVal);

                Value = newVal;
                ValueString = newVal.ToString();
                ValueInt = (int)Math.Round(newVal);

                _internalValueChanging = false;
            }
        }

        public string ValueString
        {
            get { return GetValue(ValueStringProperty) as string; }
            set { SetValue(ValueStringProperty, value); }
        }


        #endregion

        #region ValueIntProperty

        public static readonly DependencyProperty ValueIntProperty = DependencyProperty.Register("ValueInt", typeof(int), typeof(DoubleEditor), new PropertyMetadata((int)0, new PropertyChangedCallback(OnValueIntPropertyChanged)));

        private static void OnValueIntPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DoubleEditor target)
            {
                target.OnValueIntChanged((int)e.OldValue, (int)e.NewValue);
            }
        }

        private void OnValueIntChanged(int oldValue, int newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                double newVal = AdjustValue(newValue);
                Value = newVal;
                ValueString = newVal.ToString();
                ValueInt = (int)Math.Round(newVal);

                _internalValueChanging = false;
            }
        }

        public int ValueInt
        {
            get { return (int)GetValue(ValueIntProperty); }
            set { SetValue(ValueIntProperty, value); }
        }

        #endregion

        #region PrecisionProperty

        public static readonly DependencyProperty PrecisionProperty = DependencyProperty.Register("Precision", typeof(int), typeof(DoubleEditor), new PropertyMetadata((int)4, new PropertyChangedCallback(OnPrecisionPropertyChanged)));

        private static void OnPrecisionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DoubleEditor target)
            {
                target.OnPrecisionChanged((int)e.OldValue, (int)e.NewValue);
            }
        }

        private void OnPrecisionChanged(int oldValue, int newValue)
        {
            if (!_internalValueChanging)
            {
                _internalValueChanging = true;

                double newVal = AdjustValue(Value);

                Value = newVal;
                ValueString = newVal.ToString();
                ValueInt = (int)Math.Round(newVal);

                _internalValueChanging = false;
            }
        }

        public int Precision
        {
            get { return (int)GetValue(PrecisionProperty); }
            set { SetValue(PrecisionProperty, value); }
        }

        #endregion

        #region MinValueProperty

        public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(DoubleEditor), new PropertyMetadata(double.MinValue));

        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }

        #endregion

        #region MaxValueProperty

        public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(DoubleEditor), new PropertyMetadata(double.MaxValue));

        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        #endregion

        #region SmallStepValueProperty

        public static readonly DependencyProperty SmallStepValueProperty = DependencyProperty.Register("SmallStepValue", typeof(double), typeof(DoubleEditor), new PropertyMetadata((double)1));

        public double SmallStepValue
        {
            get { return (double)GetValue(SmallStepValueProperty); }
            set { SetValue(SmallStepValueProperty, value); }
        }

        #endregion

        #region LargeStepValueProperty

        public static readonly DependencyProperty LargeStepValueProperty = DependencyProperty.Register("LargeStepValue", typeof(double), typeof(DoubleEditor), new PropertyMetadata((double)10));

        public double LargeStepValue
        {
            get { return (double)GetValue(LargeStepValueProperty); }
            set { SetValue(LargeStepValueProperty, value); }
        }

        #endregion

        #region HeaderProperty

        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(DoubleEditor), new PropertyMetadata(null, new PropertyChangedCallback(OnHeaderPropertyChanged)));

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DoubleEditor target)
            {
                target.OnHeaderChanged(e.OldValue, e.NewValue);
            }
        }

        private void OnHeaderChanged(object oldVal, object newVal)
        {
            var headerContentPresenter = GetTemplateChild("HeaderContentPresenter") as UIElement;
            if (headerContentPresenter != null)
            {
                headerContentPresenter.Visibility = newVal == null ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        #endregion

        #region HeaderTemplateProperty

        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(DoubleEditor), new PropertyMetadata(null));

        public DataTemplate HeaderTemplate
        {
            get { return GetValue(HeaderTemplateProperty) as DataTemplate; }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        #endregion
    }
}


<|start_filename|>FluentEditor/App.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using FluentEditor.ControlPalette.Model;
using FluentEditor.Model;
using FluentEditor.OuterNav;
using FluentEditorShared;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;

namespace FluentEditor
{
    sealed partial class App : Application
    {
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            lock (_initLock)
            {
                if (_state != AppState.FirstLaunch)
                {
                    if (e.PrelaunchActivated == false)
                    {
                        Window.Current.Activate();
                    }
                }
                else
                {
                    _ = FirstTimeInit(e);
                }
            }
        }

        private async Task FirstTimeInit(LaunchActivatedEventArgs e)
        {
            lock(_initLock)
            {
                _state = AppState.Initializing;
            }

            await SetupDependencies();

            Window.Current.Content = new OuterNavPage(_outerNavViewModel);

            lock(_initLock)
            {
                _state = AppState.Running;
            }

            if (e.PrelaunchActivated == false)
            {
                Window.Current.Activate();
            }
        }

        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            lock (_initLock)
            {
                if (_state == AppState.Running)
                {
                    var deferral = e.SuspendingOperation.GetDeferral();
                    var suspendTask = SuspendApp(_mainNavModel, _paletteModel);
                    suspendTask.ContinueWith((t) =>
                    {
                        deferral.Complete();
                    });
                }
            }
        }

        private async Task SuspendApp(IMainNavModel mainModel, IControlPaletteModel controlPaletteModel)
        {
            await controlPaletteModel.HandleAppSuspend();
            await mainModel.HandleAppSuspend();
        }

        private async Task SetupDependencies()
        {
            var stringProvider = new StringProvider(Windows.ApplicationModel.Resources.ResourceLoader.GetForViewIndependentUse());
            var exportProvider = new ControlPaletteExportProvider();

            var paletteModel = new ControlPaletteModel();
            await paletteModel.InitializeData(stringProvider, stringProvider.GetString("ControlPaletteDataPath"));

            var navModel = new MainNavModel(stringProvider);
            await navModel.InitializeData(stringProvider.GetString("MainDataPath"), paletteModel, exportProvider);

            lock (_initLock)
            {
                _stringProvider = stringProvider;
                _exportProvider = exportProvider;

                _paletteModel = paletteModel;

                _mainNavModel = navModel;
                _outerNavViewModel = new OuterNavViewModel(_mainNavModel.NavItems, _mainNavModel.DefaultNavItem);
            }
        }

        private object _initLock = new object();
        private enum AppState { FirstLaunch, Initializing, Running }
        private AppState _state = AppState.FirstLaunch;

        private StringProvider _stringProvider;
        private ControlPaletteExportProvider _exportProvider;
        private IMainNavModel _mainNavModel;
        private IControlPaletteModel _paletteModel;

        private OuterNavViewModel _outerNavViewModel;
    }
}


<|start_filename|>FluentEditorShared/Utils/MathUtils.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.Foundation;

namespace FluentEditorShared.Utils
{
    public static class MathUtils
    {
        public static byte ClampToByte(double c)
        {
            if (double.IsNaN(c))
            {
                return 0;
            }
            else if (double.IsPositiveInfinity(c))
            {
                return 255;
            }
            else if (double.IsNegativeInfinity(c))
            {
                return 0;
            }
            c = Math.Round(c);
            if (c <= 0)
            {
                return 0;
            }
            else if (c >= 255)
            {
                return 255;
            }
            else
            {
                return (byte)c;
            }
        }

        public static double ClampToUnit(double c)
        {
            if (double.IsNaN(c))
            {
                return 0;
            }
            else if (double.IsPositiveInfinity(c))
            {
                return 1;
            }
            else if (double.IsNegativeInfinity(c))
            {
                return 0;
            }
            if (c <= 0)
            {
                return 0;
            }
            else if (c >= 1)
            {
                return 1;
            }
            else
            {
                return c;
            }
        }

        public static double DegreesToRadians(double degrees)
        {
            return degrees * (Math.PI / 180.0);
        }

        public static double RadiansToDegrees(double radians)
        {
            return radians * (180.0 / Math.PI);
        }

        public static double Lerp(double left, double right, double scale)
        {
            if (scale <= 0)
            {
                return left;
            }
            else if (scale >= 1)
            {
                return right;
            }
            return left + scale * (right - left);
        }

        public static byte Lerp(byte left, byte right, double scale)
        {
            if (scale <= 0)
            {
                return left;
            }
            else if (scale >= 1)
            {
                return right;
            }
            else if (left == right)
            {
                return left;
            }
            double l = (double)left;
            double r = (double)right;
            return (byte)Math.Round(l + scale * (r - l));
        }

        public static double LerpAnglesInDegrees(double left, double right, double scale)
        {
            if (scale <= 0)
            {
                return left;
            }
            else if (scale >= 1)
            {
                return right;
            }
            var a = (left - right + 360.0) % 360.0;
            var b = (right - left + 360.0) % 360.0;
            if (a <= b)
            {
                return (left - a * scale + 360.0) % 360.0;
            }
            else
            {
                return (left + a * scale + 360.0) % 360.0;
            }
        }

        public static double Interpolate(double start, double end, double progress, Func<double, double> easing = null)
        {
            if (progress <= 0)
            {
                return start;
            }
            else if (progress >= 1)
            {
                return end;
            }
            if (easing != null)
            {
                progress = easing(progress);
            }
            return start + (end - start) * progress;
        }

        public static Size Interpolate(in Size start, in Size end, double progress, Func<double, double> easing = null)
        {
            if (progress <= 0)
            {
                return start;
            }
            else if (progress >= 1)
            {
                return end;
            }
            if (easing != null)
            {
                progress = easing(progress);
            }
            return new Size(start.Width + (end.Width - start.Width) * progress, start.Height + (end.Height - start.Height) * progress);
        }

        public static Rect Interpolate(in Rect start, in Rect end, double progress, Func<double, double> easing = null)
        {
            if (progress <= 0)
            {
                return start;
            }
            else if (progress >= 1)
            {
                return end;
            }
            if (easing != null)
            {
                progress = easing(progress);
            }
            return new Rect(start.X + (end.X - start.X) * progress,
                       start.Y + (end.Y - start.Y) * progress,
                       start.Width + (end.Width - start.Width) * progress,
                       start.Height + (end.Height - start.Height) * progress);
        }

        public static double LinearEasing(double input)
        {
            return input;
        }

        public static double QuadraticEasing(double input)
        {
            return input * input;
        }

        public static double CubicEasing(double input)
        {
            return input * input * input;
        }

        public static double CubicBezierEasing(double x, in Point control1, in Point control2, int iterations = 4)
        {
            if (control1.X == control1.Y && control2.X == control2.Y)
            {
                return x;
            }
            double t = CubicBezierApproximateT(x, control1.X, control2.X, iterations);
            return CubicBezier(t, control1, control2).Y;
        }

        // Uses Newton Raphson method
        public static double CubicBezierApproximateT(double x, double control1, double control2, int iterations = 4)
        {
            if (x <= 0.0)
            {
                return 0.0;
            }
            if (x >= 1.0)
            {
                return 1.0;
            }

            double t = x;
            for (int i = 0; i < iterations; i++)
            {
                double slope = CubicBezierFirstDerivative(t, control1, control2);
                if (slope == 0.0)
                {
                    return t;
                }
                double xp = CubicBezier(t, control1, control2) - x;
                t -= xp / slope;
            }
            return t;
        }

        public static Point CubicBezier(double t, in Point start, in Point control1, in Point control2, in Point end)
        {
            return new Point(CubicBezier(t, start.X, control1.X, control2.X, end.X), CubicBezier(t, start.Y, control1.Y, control2.Y, end.Y));
        }

        // Special case used in easing functions where start = 0,0 and end = 1,1
        public static Point CubicBezier(double t, in Point control1, in Point control2)
        {
            return new Point(CubicBezier(t, control1.X, control2.X), CubicBezier(t, control1.Y, control2.Y));
        }

        public static double CubicBezier(double t, double start, double control1, double control2, double end)
        {
            return start * Math.Pow(1.0 - t, 3) + control1 * 3.0 * t * Math.Pow(1.0 - t, 2) + control2 * 3.0 * t * t * (1.0 - t) + t * t * t * end;
        }

        // Special case used in easing functions where start = 0 and end = 1
        public static double CubicBezier(double t, double control1, double control2)
        {
            return control1 * 3.0 * t * Math.Pow(1.0 - t, 2) + control2 * 3.0 * t * t * (1.0 - t) + t * t * t;
        }

        public static double CubicBezierFirstDerivative(double t, double start, double control1, double control2, double end)
        {
            return 3.0 * Math.Pow(1.0 - t, 2) * (control1 - start) + 6.0 * t * (1.0 - t) * (control2 - control1) + 3.0 * t * t * (end - control2);
        }

        // Special case used in easing functions where start = 0 and end = 1
        public static double CubicBezierFirstDerivative(double t, double control1, double control2)
        {
            return 3.0 * Math.Pow(1.0 - t, 2) * (control1) + 6.0 * t * (1.0 - t) * (control2 - control1) + 3.0 * t * t * (1.0 - control2);
        }

        public static double CubicBezierSecondDerivative(double t, double start, double control1, double control2, double end)
        {
            return 6.0 * (1 - t) * (control2 - 2.0 * control1 + start) + 6.0 * t * (end - 2.0 * control2 + control1);
        }

        // Special case used in easing functions where start = 0 and end = 1
        public static double CubicBezierSecondDerivative(double t, double control1, double control2)
        {
            return 6.0 * (1 - t) * (control2 - 2.0 * control1) + 6.0 * t * (1.0 - 2.0 * control2 + control1);
        }

        public static double ComputeMean(double[] values, double[] weights = null)
        {
            if (values == null || values.Length == 0)
            {
                throw new ArgumentNullException("values");
            }
            if (weights != null && weights.Length != values.Length)
            {
                throw new Exception("The weights array must be either null or the same length as values");
            }
            double totalWeight = 0.0;
            double total = 0.0;
            for (int i = 0; i < values.Length; i++)
            {
                if (weights == null)
                {
                    total += values[i];
                    totalWeight++;
                }
                else
                {
                    total += values[i] * weights[i];
                    totalWeight += weights[i];
                }
            }
            if (totalWeight == 0.0)
            {
                return 0.0;
            }
            return total / totalWeight;
        }
    }
}


<|start_filename|>FluentEditorShared/Themes/Generic.xaml.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;

namespace FluentEditorShared.Themes
{
    public sealed partial class GenericCodeBehind : ResourceDictionary
    {
        public GenericCodeBehind()
        {
            InitializeComponent();
        }
    }
}


<|start_filename|>FluentEditorShared/Utils/IPixelBlob.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.Graphics.Imaging;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public interface IPixelBlob
    {
        BitmapPixelFormat PixelFormat { get; }
        uint Width { get; }
        uint Height { get; }
        uint TotalPixels { get; }

        Color GetPixel(uint x, uint y);
        void PerPixelAction(Action<Color, uint, uint> action);
    }
}


<|start_filename|>FluentEditorShared/FluentEditorSharedResources.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;

namespace FluentEditorShared
{
    public sealed partial class FluentEditorSharedResources : ResourceDictionary
    {
        public FluentEditorSharedResources()
        {
            InitializeComponent();
        }
    }
}


<|start_filename|>FluentEditorShared/ViewCommon/VisualStateAdapter.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;

namespace FluentEditorShared.ViewCommon
{
    public class VisualStateAdapter
    {
        private List<(VisualStateGroup group, Action<VisualStateGroup, VisualState, VisualState> onChanging, Action<VisualStateGroup, VisualState, VisualState> onChanged)> _groupListeners = new List<(VisualStateGroup group, Action<VisualStateGroup, VisualState, VisualState> onChanging, Action<VisualStateGroup, VisualState, VisualState> onChanged)>();

        private FrameworkElement _containerElement = null;
        public FrameworkElement ContainerElement
        {
            get { return _containerElement; }
        }

        public VisualState GetActiveStateForGroup(string groupName)
        {
            var group = GetGroupByName(groupName);
            if (group != null)
            {
                return group.CurrentState;
            }
            return null;
        }

        public VisualStateGroup GetGroupByName(string groupName)
        {
            if (_containerElement == null)
            {
                return null;
            }
            IList<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(_containerElement);
            foreach (VisualStateGroup group in groups)
            {
                if (group.Name == groupName)
                {
                    return group;
                }
            }
            return null;
        }

        public VisualStateGroup GetGroupByStateName(string stateName)
        {
            if (_containerElement == null)
            {
                return null;
            }
            IList<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(_containerElement);
            foreach (VisualStateGroup group in groups)
            {
                foreach (VisualState state in group.States)
                {
                    if (state.Name == stateName)
                    {
                        return group;
                    }
                }
            }
            return null;
        }

        public void AddGroupListeners(string groupName, Action<VisualStateGroup, VisualState, VisualState> onChanging, Action<VisualStateGroup, VisualState, VisualState> onChanged)
        {
            if (_containerElement == null)
            {
                throw new Exception("Cannot add group listeners while not attached");
            }
            var group = GetGroupByName(groupName);
            if (group == null)
            {
                throw new ArgumentException("Could not find group with name " + groupName, "groupName");
            }

            _groupListeners.Add((group, onChanging, onChanged));
        }

        // This makes the big assumption that new states and groups are not being added or removed after Attach is called
        public void Attach(FrameworkElement containerElement)
        {
            Detach();

            _containerElement = containerElement;

            if (_containerElement == null)
            {
                return;
            }

            _containerElement.Unloaded -= _containerElement_Unloaded;
            _containerElement.Unloaded += _containerElement_Unloaded;

            IList<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(_containerElement);
            foreach (VisualStateGroup group in groups)
            {
                group.CurrentStateChanging -= Group_CurrentStateChanging;
                group.CurrentStateChanged -= Group_CurrentStateChanged;
                group.CurrentStateChanging += Group_CurrentStateChanging;
                group.CurrentStateChanged += Group_CurrentStateChanged;
            }
        }

        private void _containerElement_Unloaded(object sender, RoutedEventArgs e)
        {
            Detach();
        }

        private void Group_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
        {
            if (e.NewState == null || string.IsNullOrEmpty(e.NewState.Name))
            {
                return;
            }

            var group = GetGroupByStateName(e.NewState.Name);
            if (group == null)
            {
                return;
            }

            var listener = _groupListeners.SingleOrDefault((a) => a.group == group);
            listener.onChanged?.Invoke(group, e.OldState, e.NewState);
        }

        private void Group_CurrentStateChanging(object sender, VisualStateChangedEventArgs e)
        {
            if (e.NewState == null || string.IsNullOrEmpty(e.NewState.Name))
            {
                return;
            }

            var group = GetGroupByStateName(e.NewState.Name);
            if (group == null)
            {
                return;
            }

            var listener = _groupListeners.SingleOrDefault((a) => a.group == group);
            listener.onChanging?.Invoke(group, e.OldState, e.NewState);
        }

        public void Detach()
        {
            var containerElement = _containerElement;
            _containerElement = null;

            _groupListeners.Clear();

            if (containerElement != null)
            {
                containerElement.Unloaded -= _containerElement_Unloaded;
                IList<VisualStateGroup> groups = VisualStateManager.GetVisualStateGroups(containerElement);
                foreach (VisualStateGroup group in groups)
                {
                    group.CurrentStateChanging -= Group_CurrentStateChanging;
                    group.CurrentStateChanged -= Group_CurrentStateChanged;
                }
            }
        }
    }
}


<|start_filename|>FluentEditorShared/Utils/BitmapUtils.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Windows.UI;

namespace FluentEditorShared.Utils
{
    public static class BitmapUtils
    {
        public static (double min, double average, double max)[] ComputeContrastRatioForImage(IPixelBlob pixels, Color[] testColors)
        {
            (double min, double average, double max)[] retVal = new(double min, double average, double max)[testColors.Length];
            for (int i = 0; i < testColors.Length; i++)
            {
                retVal[i].min = double.MaxValue;
            }
            double count = 0;
            pixels.PerPixelAction((c, x, y) =>
            {
                count++;
                for (int i = 0; i < testColors.Length; i++)
                {
                    var ratio = ColorUtils.ContrastRatio(c, testColors[i], false);
                    retVal[i].average += ratio;
                    retVal[i].min = Math.Min(retVal[i].min, ratio);
                    retVal[i].max = Math.Max(retVal[i].max, ratio);
                }
            });
            for (int i = 0; i < testColors.Length; i++)
            {
                retVal[i].average /= count;
            }
            return retVal;
        }
    }
}


<|start_filename|>FluentEditorShared/ViewCommon/ExtensibleVisualStateManager.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.ViewCommon
{
    public class ExtensibleVisualStateManager : VisualStateManager
    {
        protected override bool GoToStateCore(Control control, FrameworkElement templateRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
        {
            if (templateRoot == null)
            {
                return base.GoToStateCore(control, templateRoot, stateName, group, state, useTransitions);
            }
            else
            {
                IControlTemplateExtension extension = ExtensibleVisualStateManagerProperties.GetVisualStateManagerExtension(templateRoot);

                if (extension != null)
                {
                    bool callCore = false;
                    bool retVal = extension.HandleStateChange(out callCore, control, templateRoot, stateName, group, state, useTransitions);
                    if (callCore)
                    {
                        return base.GoToStateCore(control, templateRoot, stateName, group, state, useTransitions);
                    }
                    else
                    {
                        return retVal;
                    }
                }
                else
                {
                    return base.GoToStateCore(control, templateRoot, stateName, group, state, useTransitions);
                }
            }
        }
    }

    public interface IControlTemplateExtension
    {
        bool HandleStateChange(out bool callGoToStateCore, Control control, FrameworkElement templateRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions);
    }

    public class PassthroughExtension : IControlTemplateExtension
    {
        public bool HandleStateChange(out bool callGoToStateCore, Control control, FrameworkElement templateRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
        {
            if (control is IControlTemplateExtension controlHandler)
            {
                return controlHandler.HandleStateChange(out callGoToStateCore, control, templateRoot, stateName, group, state, useTransitions);
            }
            else
            {
                callGoToStateCore = true;
                return true;
            }
        }
    }

    public static class ExtensibleVisualStateManagerProperties
    {
        private static object _stateManagersLock = new object();
        private static Dictionary<CoreDispatcher, ExtensibleVisualStateManager> _stateManagers = new Dictionary<CoreDispatcher, ExtensibleVisualStateManager>();

        public static ExtensibleVisualStateManager GetManagerForDispatcher(CoreDispatcher dispatcher)
        {
            if (!dispatcher.HasThreadAccess)
            {
                throw new InvalidOperationException("Current thread does not match provided dispatcher");
            }
            lock (_stateManagersLock)
            {
                if (_stateManagers.ContainsKey(dispatcher))
                {
                    return _stateManagers[dispatcher];
                }
                else
                {
                    ExtensibleVisualStateManager manager = new ExtensibleVisualStateManager();
                    _stateManagers.Add(dispatcher, manager);
                    return manager;
                }
            }
        }

        // In the event that we need to clear out the manager for a given Dispatcher
        // If closing a window with its own Dispatcher thread this might be needed
        public static void ClearResourcesForDispatcher(CoreDispatcher dispatcher)
        {
            lock (_stateManagersLock)
            {
                if (_stateManagers.ContainsKey(dispatcher))
                {
                    _stateManagers.Remove(dispatcher);
                }
            }
        }

        public static readonly DependencyProperty ControlTemplateExtensionProperty = DependencyProperty.Register("VisualStateManagerExtension", typeof(IControlTemplateExtension), typeof(ExtensibleVisualStateManagerProperties), new PropertyMetadata(null, new PropertyChangedCallback(OnControlTemplateExtensionPropertyChanged)));

        private static void OnControlTemplateExtensionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameworkElement element)
            {
                IControlTemplateExtension newValue = e.NewValue as IControlTemplateExtension;

                if (newValue != null)
                {
                    VisualStateManager.SetCustomVisualStateManager(element, GetManagerForDispatcher(element.Dispatcher));
                }
                else
                {
                    VisualStateManager.SetCustomVisualStateManager(element, null);
                }
            }
        }

        public static IControlTemplateExtension GetVisualStateManagerExtension(DependencyObject d)
        {
            return d.GetValue(ControlTemplateExtensionProperty) as IControlTemplateExtension;
        }

        public static void SetVisualStateManagerExtension(DependencyObject d, IControlTemplateExtension value)
        {
            d.SetValue(ControlTemplateExtensionProperty, value);
        }
    }
}


<|start_filename|>FluentEditorShared/ColorPalette/IColorPalette.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;

namespace FluentEditorShared.ColorPalette
{
    // These classes are not intended to be viewmodels.
    // They deal with the data about an editable palette and are passed to special purpose controls for editing
    public interface IColorPalette
    {
        IColorPaletteEntry BaseColor { get; }
        int Steps { get; }
        IReadOnlyList<EditableColorPaletteEntry> Palette { get; }
        IReadOnlyList<ContrastColorWrapper> ContrastColors { get; set; }
    }
}


<|start_filename|>FluentEditor/ControlPalette/ControlPaletteTestContent.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditor.ControlPalette
{
    public sealed partial class ControlPaletteTestContent : UserControl
    {
        public ControlPaletteTestContent()
        {
            this.InitializeComponent();
        }

        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(ControlPaletteTestContent), new PropertyMetadata(null));

        public string Title
        {
            get { return GetValue(TitleProperty) as string; }
            set { SetValue(TitleProperty, value); }
        }
    }
}


<|start_filename|>FluentEditorShared/AnimAttachedProperties.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Numerics;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;

namespace FluentEditorShared
{
    public static class AnimAttachedProperties
    {
        #region TranslateCubicProperty

        // duration,delay,controlPoint1X,controlPoint1Y,controlPoint2X,controlPoint2Y
        public static DependencyProperty TranslateCubicProperty = DependencyProperty.RegisterAttached("TranslateCubic", typeof(string), typeof(AnimAttachedProperties), new PropertyMetadata(null, new PropertyChangedCallback(OnTranslateCubicPropertyChanged)));

        public static string GetTranslateCubic(DependencyObject d)
        {
            return d.GetValue(TranslateCubicProperty) as string;
        }

        public static void SetTranslateCubic(DependencyObject d, string value)
        {
            d.SetValue(TranslateCubicProperty, value);
        }

        private static void OnTranslateCubicPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            Visual targetVisual = null;
            if (target is UIElement targetElement)
            {
                targetVisual = ElementCompositionPreview.GetElementVisual(targetElement);
            }
            if (targetVisual == null)
            {
                return;
            }

            bool valid = false;
            Vector2 point1 = Vector2.Zero;
            Vector2 point2 = Vector2.Zero;
            TimeSpan duration = TimeSpan.Zero;
            TimeSpan? delay = null;

            if (e.NewValue == null || (e.NewValue as string) == string.Empty)
            {
                // Remove existing implicit anim on offset if any
                if (targetVisual.ImplicitAnimations != null && targetVisual.ImplicitAnimations.ContainsKey("Offset"))
                {
                    targetVisual.ImplicitAnimations.Remove("Offset");
                }
                return;
            }
            if (e.NewValue is string raw)
            {
                string[] rawPoints = raw.Split(",");
                if (rawPoints != null && rawPoints.Length == 6)
                {
                    if (rawPoints[1] != string.Empty && TimeSpan.TryParse(rawPoints[1], out TimeSpan de))
                    {
                        delay = de;
                    }

                    if (TimeSpan.TryParse(rawPoints[0], out duration))
                    {
                        if (float.TryParse(rawPoints[2], out float a))
                        {
                            if (float.TryParse(rawPoints[3], out float b))
                            {
                                if (float.TryParse(rawPoints[4], out float c))
                                {
                                    if (float.TryParse(rawPoints[5], out float d))
                                    {
                                        valid = true;
                                        point1 = new Vector2(a, b);
                                        point2 = new Vector2(c, d);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (!valid)
            {
                return;
            }

            var compositor = Window.Current.Compositor;
            var easing = compositor.CreateCubicBezierEasingFunction(point1, point2);
            var anim = compositor.CreateVector3KeyFrameAnimation();
            if (delay.HasValue)
            {
                anim.DelayTime = delay.Value;
            }
            anim.Duration = duration;
            anim.InsertExpressionKeyFrame(1.0f, "this.FinalValue", easing);

            if (targetVisual.ImplicitAnimations == null)
            {
                targetVisual.ImplicitAnimations = compositor.CreateImplicitAnimationCollection();
            }
            if (!targetVisual.ImplicitAnimations.ContainsKey("Offset"))
            {
                targetVisual.ImplicitAnimations.Add("Offset", anim);
            }
            else
            {
                targetVisual.ImplicitAnimations["Offset"] = anim;
            }
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/Utils/VisualTreeHelpers.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;

namespace FluentEditorShared.Utils
{
    public static class VisualTreeHelpers
    {
        // This should only be called on the dispatcher thread associated with parent
        public static T FindElementByName<T>(DependencyObject parent, string name) where T : FrameworkElement
        {
            if (parent == null || name == null)
            {
                return null;
            }
            if (parent is T d)
            {
                if (d.Name == name)
                {
                    return d;
                }
            }
            int count = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < count; i++)
            {
                var retVal = FindElementByName<T>(VisualTreeHelper.GetChild(parent, i), name);
                if (retVal != null)
                {
                    return retVal;
                }
            }
            return null;
        }
    }
}


<|start_filename|>FluentEditorShared/ObjectPool/ObjectPool.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace FluentEditorShared.ObjectPool
{
    public class ObjectPool<T> : IObjectPool<T> where T : IPoolableObject
    {
        public ObjectPool(int initialSize, Func<T> factory, double growthFactor = 1.5)
        {
            if (initialSize <= 1)
            {
                throw new ArgumentException("initialSize must be at least 2");
            }
            if(growthFactor <= 1f)
            {
                throw new ArgumentException("growthFactor must be greater than 1.0");
            }
            if (factory == null)
            {
                throw new ArgumentNullException("factory");
            }
            _factory = factory;
            _growthFactor = growthFactor;
            _pool = new T[initialSize];
            for (int i = 0; i < _pool.Length; i++)
            {
                _pool[i] = _factory();
                _pool[i].Reset();
            }
            _currentIndex = 0;
        }

        private object _lock = new object();

        private readonly Func<T> _factory;
        private readonly double _growthFactor;
        private T[] _pool;

        private int _currentIndex;

        public T GetObject()
        {
            lock (_lock)
            {
                if (!_pool[_currentIndex].IsLive)
                {
                    T target = _pool[_currentIndex];
                    _currentIndex++;
                    if (_currentIndex >= _pool.Length)
                    {
                        _currentIndex = 0;
                    }
                    target.Activate();
                    return target;
                }
                for (int i = 0; i < _pool.Length; i++)
                {
                    int index = (i + _currentIndex) % _pool.Length;

                    if (!_pool[index].IsLive)
                    {
                        T target = _pool[index];
                        _currentIndex = index + 1;
                        if (_currentIndex >= _pool.Length)
                        {
                            _currentIndex = 0;
                        }
                        target.Activate();
                        return target;
                    }
                }

                // Resize needed. If this happens at all frequently then initialSize and / or growthFactor are too small. 
                int firstNewIndex = _pool.Length;

                double rawNewSize = Math.Ceiling((double)_pool.Length * _growthFactor);
                if (rawNewSize >= (double)int.MaxValue)
                {
                    throw new Exception("Object pool attempting to grow larger than int.MaxValue");
                }
                int newSize = (int)rawNewSize;

                Array.Resize(ref _pool, newSize);
                for(int i=firstNewIndex;i<_pool.Length;i++)
                {
                    _pool[i] = _factory();
                    _pool[i].Reset();
                }

                T resizedTarget = _pool[firstNewIndex];
                _currentIndex = firstNewIndex + 1;
                if(_currentIndex >= _pool.Length)
                {
                    _currentIndex = 0;
                }
                resizedTarget.Activate();
                return resizedTarget;
            }
        }

        public void ReturnObject(T target)
        {
            lock (_lock)
            {
                if (target == null)
                {
                    throw new ArgumentNullException("target");
                }
                target.Reset();
            }
        }
    }
}


<|start_filename|>FluentEditorShared/DelegateCommand.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Windows.Input;

namespace FluentEditorShared
{
    // Not thread safe, but allows changing the delegate
    public class DelegateCommand : ICommand
    {
        public DelegateCommand()
        { }

        public DelegateCommand(Action<object> del)
        {
            _delegate = del;
        }

        private Action<object> _delegate = null;
        public Action<object> Delegate
        {
            get
            {
                return _delegate;
            }
            set
            {
                if (_delegate != null)
                {
                    _delegate = value;
                    RaiseCanExecuteChanged();
                }
            }
        }

        #region ICommand

        public event EventHandler CanExecuteChanged;

        private void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, new EventArgs());
        }

        public bool CanExecute(object parameter)
        {
            return _delegate != null;
        }

        public void Execute(object parameter)
        {
            if (CanExecute(parameter))
            {
                _delegate(parameter);
            }
        }

        #endregion
    }

    // Immutable, this is thread safe though the delegate it points to might not be
    public class ImmutableDelegateCommand : ICommand
    {
        public ImmutableDelegateCommand(Action<object> del)
        {
            if (del == null)
            {
                throw new ArgumentNullException("del");
            }
            _delegate = del;
        }

        private readonly Action<object> _delegate = null;
        public Action<object> Delegate
        {
            get { return _delegate; }
        }

        #region ICommand

        // This must be included for the ICommand interface but is never used in an ImmutableDelegateCommand
        #pragma warning disable CS0067
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _delegate(parameter);
        }

        #endregion
    }
}



<|start_filename|>FluentEditor/ControlPalette/ControlPaletteResources.xaml.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using Windows.UI.Xaml;

namespace FluentEditor.ControlPalette
{
    public sealed partial class ControlPaletteResources : ResourceDictionary
    {
        public ControlPaletteResources()
        {
            this.InitializeComponent();
        }

        private List<ColorMappingInstance> _lightColorMappings;
        private List<ColorMappingInstance> _darkColorMappings;

        #region LinkedElementProperty

        public static readonly DependencyProperty LinkedElementProperty = DependencyProperty.Register("LinkedElement", typeof(FrameworkElement), typeof(ControlPaletteResources), new PropertyMetadata(null, new PropertyChangedCallback(OnLinkedElementPropertyChanged)));

        private static void OnLinkedElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ControlPaletteResources target)
            {
                target.OnLinkedElementChanged(e.OldValue as FrameworkElement, e.NewValue as FrameworkElement);
            }
        }

        private void OnLinkedElementChanged(FrameworkElement oldValue, FrameworkElement newValue)
        {
            if (_lightColorMappings != null)
            {
                foreach (var mapping in _lightColorMappings)
                {
                    mapping.LinkedElement = newValue;
                }
            }
            if (_darkColorMappings != null)
            {
                foreach (var mapping in _darkColorMappings)
                {
                    mapping.LinkedElement = newValue;
                }
            }
        }

        public FrameworkElement LinkedElement
        {
            get { return GetValue(LinkedElementProperty) as FrameworkElement; }
            set { SetValue(LinkedElementProperty, value); }
        }

        #endregion

        #region LightColorMappingProperty

        public static readonly DependencyProperty LightColorMappingProperty = DependencyProperty.Register("LightColorMapping", typeof(IReadOnlyList<ColorMapping>), typeof(ControlPaletteResources), new PropertyMetadata(null, new PropertyChangedCallback(OnLightColorMappingPropertyChanged)));

        private static void OnLightColorMappingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ControlPaletteResources target)
            {
                target.OnLightColorMappingChanged(e.OldValue as IReadOnlyList<ColorMapping>, e.NewValue as IReadOnlyList<ColorMapping>);
            }
        }

        private void OnLightColorMappingChanged(IReadOnlyList<ColorMapping> oldValue, IReadOnlyList<ColorMapping> newValue)
        {
            if (_lightColorMappings != null && _lightColorMappings.Count > 0)
            {
                for (int i = 0; i < _lightColorMappings.Count; i++)
                {
                    _lightColorMappings[i].Dispose();
                }
                _lightColorMappings.Clear();
                _lightColorMappings = null;
            }

            if (newValue != null && newValue.Count > 0)
            {
                var linkedElement = LinkedElement;
                _lightColorMappings = new List<ColorMappingInstance>(newValue.Count);
                for (int i = 0; i < newValue.Count; i++)
                {
                    var instance = newValue[i].CreateInstance(LightColorPaletteResources);
                    instance.LinkedElement = linkedElement;
                    _lightColorMappings.Add(instance);
                }
            }
        }

        public IReadOnlyList<ColorMapping> LightColorMapping
        {
            get { return GetValue(LightColorMappingProperty) as IReadOnlyList<ColorMapping>; }
            set { SetValue(LightColorMappingProperty, value); }
        }

        #endregion

        #region DarkColorMappingProperty

        public static readonly DependencyProperty DarkColorMappingProperty = DependencyProperty.Register("DarkColorMapping", typeof(IReadOnlyList<ColorMapping>), typeof(ControlPaletteResources), new PropertyMetadata(null, new PropertyChangedCallback(OnDarkColorMappingPropertyChanged)));

        private static void OnDarkColorMappingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ControlPaletteResources target)
            {
                target.OnDarkColorMappingChanged(e.OldValue as IReadOnlyList<ColorMapping>, e.NewValue as IReadOnlyList<ColorMapping>);
            }
        }

        private void OnDarkColorMappingChanged(IReadOnlyList<ColorMapping> oldValue, IReadOnlyList<ColorMapping> newValue)
        {
            if (_darkColorMappings != null && _darkColorMappings.Count > 0)
            {
                for (int i = 0; i < _darkColorMappings.Count; i++)
                {
                    _darkColorMappings[i].Dispose();
                }
                _darkColorMappings.Clear();
                _darkColorMappings = null;
            }

            if (newValue != null && newValue.Count > 0)
            {
                var linkedElement = LinkedElement;
                _darkColorMappings = new List<ColorMappingInstance>(newValue.Count);
                for (int i = 0; i < newValue.Count; i++)
                {
                    var instance = newValue[i].CreateInstance(DarkColorPaletteResources);
                    instance.LinkedElement = linkedElement;
                    _darkColorMappings.Add(instance);
                }
            }
        }

        public IReadOnlyList<ColorMapping> DarkColorMapping
        {
            get { return GetValue(DarkColorMappingProperty) as IReadOnlyList<ColorMapping>; }
            set { SetValue(DarkColorMappingProperty, value); }
        }

        #endregion
    }
}


<|start_filename|>FluentEditorShared/ViewCommon/IView.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace FluentEditorShared.ViewCommon
{
    public delegate IView ViewFactoryDelegate(object viewModel);

    public interface IView
    {
        // It is desirable to have strong typing from View to ViewModel to allow for x:Bind
        // but type erasure can also be useful here. The usual implementation of AttachViewModel is just this.ViewModel = viewModel as MyVMType.
        void AttachViewModel(object viewModel);
        void DetachViewModel();

        ViewFactoryDelegate ViewFactory { get; set; }
    }
}


<|start_filename|>FluentEditorShared/Editors/ErrorText.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace FluentEditorShared.Editors
{
    public class ErrorText : Control
    {
        public ErrorText()
        {
            this.DefaultStyleKey = typeof(ErrorText);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            UpdateState();
        }

        private void UpdateState()
        {
            if(ShowErrorState)
            {
                VisualStateManager.GoToState(this, "ErrorStateActive", true);
            }
            else
            {
                VisualStateManager.GoToState(this, "ErrorStateInactive", true);
            }
        }

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ErrorText), new PropertyMetadata(null));

        public string Text
        {
            get { return GetValue(TextProperty) as string; }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty ShowErrorStateProperty = DependencyProperty.Register("ShowErrorState", typeof(bool), typeof(ErrorText), new PropertyMetadata(false, new PropertyChangedCallback(OnShowErrorStatePropertyChanged)));

        private static void OnShowErrorStatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ErrorText target)
            {
                target.UpdateState();
            }
        }

        public bool ShowErrorState
        {
            get { return (bool)GetValue(ShowErrorStateProperty); }
            set { SetValue(ShowErrorStateProperty, value); }
        }
    }
}


<|start_filename|>FluentEditor/Model/MainNavModel.cs<|end_filename|>
﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using FluentEditor.OuterNav;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Data.Json;
using Windows.Storage;
using FluentEditorShared.Utils;
using FluentEditor.ControlPalette.Model;
using FluentEditorShared;

namespace FluentEditor.Model
{
    public interface IMainNavModel
    {
        Task InitializeData(string dataPath, IControlPaletteModel paletteModel, ControlPaletteExportProvider controlPaletteExportProvider);
        Task HandleAppSuspend();

        IReadOnlyList<INavItem> NavItems { get; }
        INavItem DefaultNavItem { get; }
    }

    public class MainNavModel : IMainNavModel
    {
        public MainNavModel(IStringProvider stringProvider)
        {
            _stringProvider = stringProvider;
        }

        private IStringProvider _stringProvider;

        public async Task InitializeData(string dataPath, IControlPaletteModel paletteModel, ControlPaletteExportProvider controlPaletteExportProvider)
        {
            StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(dataPath));
            string dataString = await FileIO.ReadTextAsync(file);
            JsonObject rootObject = JsonObject.Parse(dataString);

            List<INavItem> navItems = new List<INavItem>();

            if (rootObject.ContainsKey("Demos"))
            {
                JsonArray demoDataList = rootObject["Demos"].GetArray();
                foreach (var demoData in demoDataList)
                {
                    navItems.Add(ParseNavItem(demoData.GetObject(), paletteModel, controlPaletteExportProvider));
                }
            }

            string defaultDemoId = rootObject.GetOptionalString("DefaultDemoId");
            if (!string.IsNullOrEmpty(defaultDemoId))
            {
                _defaultNavItem = navItems.FirstOrDefault((a) => a.Id == defaultDemoId);
            }

            _navItems = navItems;
        }

        public Task HandleAppSuspend()
        {
            // Currently nothing to do here
            return Task.CompletedTask;
        }

        private INavItem ParseNavItem(JsonObject data, IControlPaletteModel paletteModel, ControlPaletteExportProvider controlPaletteExportProvider)
        {
            string type = data.GetOptionalString("Type");

            switch (type)
            {
                case "ControlPalette":
                    return ControlPalette.ControlPaletteViewModel.Parse(_stringProvider, data, paletteModel, controlPaletteExportProvider);
                default:
                    throw new Exception(string.Format("Unknown nav item type {0}", type));
            }
        }

        private List<INavItem> _navItems = null;
        public IReadOnlyList<INavItem> NavItems
        {
            get { return _navItems; }
        }

        private INavItem _defaultNavItem = null;
        public INavItem DefaultNavItem
        {
            get { return _defaultNavItem; }
        }
    }
}
