using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Security.Policy;
using System.Diagnostics;
using NLog;
using SpineViewer.Utils;
using System.Drawing.Design;
using System.Reflection;
using System.Resources;
using SpineViewer.Utils.Localize;

namespace SpineViewer.Controls
{
    public partial class SpinePreviewPanel : UserControl
    {
        public SpinePreviewPanel()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 日志器
        /// </summary>
        private readonly Logger logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 要绑定的 Spine 列表控件
        /// </summary>
        [LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDescription(typeof(Properties.Resources), "descAssociatedSpineListView")]
        public SpineListView? SpineListView { get; set; }

		/// <summary>
		/// 属性信息面板
		/// </summary>
		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDescription(typeof(Properties.Resources), "descDisplayImageProperties")]
		public PropertyGrid? PropertyGrid
        {        
            get => propertyGrid;
            set
            {
                propertyGrid = value;
                if (propertyGrid is not null)
                    propertyGrid.SelectedObject = new SpinePreviewPanelProperty(this);
            }
        }
        private PropertyGrid? propertyGrid;

        #region 参数属性

        /// <summary>
        /// 分辨率
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public Size Resolution
        {
            get => resolution;
            set
            {
                if (renderWindow is null) return;

                if (value == resolution) return;
                if (value.Width <= 0) value.Width = 100;
                if (value.Height <= 0) value.Height = 100;

                var previousZoom = Zoom;

                float parentW = panel_Render.Parent.Width;
                float parentH = panel_Render.Parent.Height;
                float renderW = value.Width;
                float renderH = value.Height;
                float scale = Math.Min(parentW / renderW, parentH / renderH); // 两方向取较小值, 保证 parent 覆盖 render
                renderW *= scale;
                renderH *= scale;

                panel_Render.Location = new((int)((parentW - renderW) / 2 + 0.5), (int)((parentH - renderH) / 2 + 0.5));
                panel_Render.Size = new((int)(renderW + 0.5), (int)(renderH + 0.5));
                resolution = value;

                // 设置完 resolution 后还原缩放比例
                Zoom = previousZoom;

                // 设置壁纸窗口分辨率
                using var view = renderWindow.GetView();
                wallpaperWindow.SetView(view);
                wallpaperForm.Size = value; // 必须两个 Size 都设置
                wallpaperWindow.Size = new((uint)value.Width, (uint)value.Height);
            }
        }
        private Size resolution = new(100, 100);

        /// <summary>
        /// 画面中心点
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public PointF Center
        {
            get
            {
                if (renderWindow is null) return new(-1, -1);

                using var view = renderWindow.GetView();
                var center = view.Center;
                return new(center.X, center.Y);
            }
            set
            {
                if (renderWindow is null) return;

                using var view = renderWindow.GetView();
                view.Center = new(value.X, value.Y);
                renderWindow.SetView(view);
                wallpaperWindow.SetView(view);
            }
        }

        /// <summary>
        /// 画面缩放
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public float Zoom
        {
            get
            {
                if (renderWindow is null) return -1;

                using var view = renderWindow.GetView();
                return resolution.Width / Math.Abs(view.Size.X);
            }
            set
            {
                if (renderWindow is null) return;

                value = Math.Clamp(value, 0.001f, 1000f);
                using var view = renderWindow.GetView();
                var signX = Math.Sign(view.Size.X);
                var signY = Math.Sign(view.Size.Y);
                view.Size = new(resolution.Width / value * signX, resolution.Height / value * signY);
                renderWindow.SetView(view);
                wallpaperWindow.SetView(view);
            }
        }

        /// <summary>
        /// 画面旋转
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public float Rotation
        {
            get
            {
                if (renderWindow is null) return -1;

                using var view = renderWindow.GetView();
                return view.Rotation;
            }
            set
            {
                if (renderWindow is null) return;

                using var view = renderWindow.GetView();
                view.Rotation = value;
                renderWindow.SetView(view);
                wallpaperWindow.SetView(view);
            }
        }

        /// <summary>
        /// 水平翻转
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool FlipX
        {
            get
            {
                if (renderWindow is null) return false;

                using var view = renderWindow.GetView();
                return view.Size.X < 0;
            }
            set
            {
                if (renderWindow is null) return;

                using var view = renderWindow.GetView();
                var size = view.Size;
                if (size.X > 0 && value || size.X < 0 && !value)
                    size.X *= -1;
                view.Size = size;
                renderWindow.SetView(view);
                wallpaperWindow.SetView(view);
            }
        }

        /// <summary>
        /// 垂直翻转
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool FlipY
        {
            get
            {
                if (renderWindow is null) return false;

                using var view = renderWindow.GetView();
                return view.Size.Y < 0;
            }
            set
            {
                if (renderWindow is null) return;

                using var view = renderWindow.GetView();
                var size = view.Size;
                if (size.Y > 0 && value || size.Y < 0 && !value)
                    size.Y *= -1;
                view.Size = size;
                renderWindow.SetView(view);
                wallpaperWindow.SetView(view);
            }
        }

        /// <summary>
        /// 仅渲染选中
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool RenderSelectedOnly { get; set; } = false;

        /// <summary>
        /// 显示坐标轴
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool ShowAxis { get; set; } = true;

        /// <summary>
        /// 最大帧率
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public uint MaxFps
        {
            get => maxFps;
            set
            {
                if (renderWindow is null) return;

                renderWindow.SetFramerateLimit(value);
                maxFps = value;
            }
        }
        private uint maxFps = 60;

        /// <summary>
        /// 获取 View
        /// </summary>
        public SFML.Graphics.View GetView() => renderWindow.GetView();

        /// <summary>
        /// 是否开启桌面投影
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool EnableDesktopProjection
        {
            get => enableDesktopProjection;
            set
            {
                if (renderWindow is null) return;

                if (enableDesktopProjection == value) return;
                if (value)
                {
                    var screenBounds = Screen.FromControl(this).Bounds;
                    Resolution = screenBounds.Size;
                    wallpaperWindow.Position = new(screenBounds.X, screenBounds.Y);
                    wallpaperForm.Show();
                }
                else
                {
                    wallpaperForm.Hide();
                }
                enableDesktopProjection = value;
            }
        }
        private bool enableDesktopProjection = false;

        /// <summary>
        /// 预览画面背景色
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public SFML.Graphics.Color BackgroundColor { get; set; } = new(105, 105, 105);

        #endregion

        #region 渲染管理

        /// <summary>
        /// 预览画面坐标轴颜色
        /// </summary>
        private static readonly SFML.Graphics.Color AxisColor = new(220, 220, 220);

        /// <summary>
        /// 坐标轴顶点缓冲区
        /// </summary>
        private readonly SFML.Graphics.VertexArray axisVertices = new(SFML.Graphics.PrimitiveType.Lines, 2); // XXX: 暂时未使用 Dispose 释放

        /// <summary>
        /// 渲染窗口
        /// </summary>
        private SFML.Graphics.RenderWindow renderWindow;

        /// <summary>
        /// 壁纸窗口
        /// </summary>
        private SFML.Graphics.RenderWindow wallpaperWindow;

        /// <summary>
        /// 帧间隔计时器
        /// </summary>
        private readonly SFML.System.Clock clock = new();

        /// <summary>
        /// 渲染任务
        /// </summary>
        private Task? task = null;
        private CancellationTokenSource? cancelToken = null;

        /// <summary>
        /// 是否更新画面
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public bool IsUpdating
        {
            get => isUpdating;
            private set
            {
                if (value == isUpdating) return;
                if (value)
                {
                    button_Start.ImageKey = "pause";
                }
                else
                {
                    button_Start.ImageKey = "start";
                }
                isUpdating = value;
            }
        }
        private bool isUpdating = true;

        /// <summary>
        /// 快进时间量
        /// </summary>
        private float forwardDelta = 0;
        private object _forwardDeltaLock = new();

        /// <summary>
        /// 开始渲染
        /// </summary>
        public void StartRender()
        {
            // 延迟到第一次开启渲染时进行初始化
            if (renderWindow is null)
            {
                renderWindow = new(panel_Render.Handle);
                renderWindow.SetActive(false);
                wallpaperWindow = new(wallpaperForm.Handle);
                wallpaperWindow.SetActive(false);

                // 设置默认参数
                Resolution = new(2048, 2048);
                Zoom = 1;
                Center = new(0, 0);
                FlipY = true;
                MaxFps = 30;
            }

            if (task is not null) return;
            cancelToken = new();
            task = Task.Run(RenderTask, cancelToken.Token);
            IsUpdating = true;
            if (enableDesktopProjection) wallpaperForm.Show();
        }

        /// <summary>
        /// 停止渲染
        /// </summary>
        public void StopRender()
        {
            if (wallpaperForm.InvokeRequired) wallpaperForm.Invoke(wallpaperForm.Hide);
            else wallpaperForm.Hide();
            IsUpdating = false;
            if (task is null || cancelToken is null)
                return;
            cancelToken.Cancel();
            task.Wait();
            cancelToken = null;
            task = null;
        }

        /// <summary>
        /// 渲染任务
        /// </summary>
        private void RenderTask()
        {
            try
            {
                renderWindow.SetActive(true);
                wallpaperWindow.SetActive(true);

                float delta;
                while (cancelToken is not null && !cancelToken.IsCancellationRequested)
                {
                    // 必须让 SFML 有机会处理窗口消息, 例如位置和大小变化
                    renderWindow.DispatchEvents();

                    delta = clock.ElapsedTime.AsSeconds();
                    clock.Restart();

                    // 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象
                    if (!IsUpdating) delta = 0;

                    // 加上要快进的量
                    lock (_forwardDeltaLock)
                    {
                        delta += forwardDelta;
                        forwardDelta = 0;
                    }

                    renderWindow.Clear(BackgroundColor);
                    if (enableDesktopProjection) wallpaperWindow.Clear(BackgroundColor);

                    if (ShowAxis)
                    {
                        // 画一个很长的坐标轴, 用 1e9 比较合适
                        axisVertices[0] = new(new(-1e9f, 0), AxisColor);
                        axisVertices[1] = new(new(1e9f, 0), AxisColor);
                        renderWindow.Draw(axisVertices);
                        axisVertices[0] = new(new(0, -1e9f), AxisColor);
                        axisVertices[1] = new(new(0, 1e9f), AxisColor);
                        renderWindow.Draw(axisVertices);
                    }

                    // 渲染 Spine
                    if (SpineListView is not null)
                    {
                        lock (SpineListView.Spines)
                        {
                            var spines = SpineListView.Spines.Where(sp => !sp.IsHidden).ToArray();
                            for (int i = spines.Length - 1; i >= 0; i--)
                            {
                                if (cancelToken is not null && cancelToken.IsCancellationRequested)
                                    break; // 提前中止

                                var spine = spines[i];

                                spine.Update(delta);

                                if (RenderSelectedOnly && !spine.IsSelected)
                                    continue;

                                spine.EnableDebug = true;
                                renderWindow.Draw(spine);
                                spine.EnableDebug = false;

                                if (enableDesktopProjection) wallpaperWindow.Draw(spine);
                            }
                        }
                    }

                    renderWindow.Display();

                    if (enableDesktopProjection) wallpaperWindow.Display();
                }
            }
            catch (Exception ex)
            {
                logger.Fatal(ex.ToString());
                logger.Fatal("Render task stopped");
                MessagePopup.Error(ex.ToString(), Properties.Resources.previewRenderStopped);
            }
            finally
            {
                renderWindow.SetActive(false);
                wallpaperWindow.SetActive(false);
            }
        }

        #endregion

        /// <summary>
        /// 画面拖放对象世界坐标源点
        /// </summary>
        private SFML.System.Vector2f? draggingSrc = null;

        private void panel_RenderContainer_SizeChanged(object sender, EventArgs e)
        {
            
            if (renderWindow is null) return;

            float parentW = panel_Render.Parent.Width;
            float parentH = panel_Render.Parent.Height;
            float renderW = panel_Render.Width;
            float renderH = panel_Render.Height;
            float scale = Math.Min(parentW / renderW, parentH / renderH); // 两方向取较小值, 保证 parent 覆盖 render
            renderW *= scale;
            renderH *= scale;

            panel_Render.Location = new((int)((parentW - renderW) / 2 + 0.5), (int)((parentH - renderH) / 2 + 0.5));
            panel_Render.Size = new((int)(renderW + 0.5), (int)(renderH + 0.5));
        }

        private void panel_Render_MouseDown(object sender, MouseEventArgs e)
        {
            if (renderWindow is null) return;

            // 右键优先级高, 进入画面拖动模式, 需要重新记录源点
            if ((e.Button & MouseButtons.Right) != 0)
            {
                draggingSrc = renderWindow.MapPixelToCoords(new(e.X, e.Y));
                Cursor = Cursors.Hand;
            }
            // 按下了左键并且右键是松开的
            else if ((e.Button & MouseButtons.Left) != 0 && (MouseButtons & MouseButtons.Right) == 0)
            {
                draggingSrc = renderWindow.MapPixelToCoords(new(e.X, e.Y));
                var src = new PointF(((SFML.System.Vector2f)draggingSrc).X, ((SFML.System.Vector2f)draggingSrc).Y);

                if (SpineListView is null)
                    return;

                lock (SpineListView.Spines)
                {
                    var spines = SpineListView.Spines;

                    // 仅渲染选中模式禁止在画面里选择对象
                    if (RenderSelectedOnly)
                    {
                        // 只在被选中的对象里判断是否有效命中
                        bool hit = false;
                        foreach (int i in SpineListView.SelectedIndices)
                        {
                            if (spines[i].IsHidden) continue;
                            if (!spines[i].GetCurrentBounds().Contains(src)) continue;
                            hit = true;
                            break;
                        }

                        // 如果没点到被选中的模型, 则不允许拖动
                        if (!hit) draggingSrc = null;
                    }
                    else
                    {
                        if ((ModifierKeys & Keys.Control) == 0)
                        {
                            // 没按 Ctrl 的情况下, 如果命中了已选中对象, 则就算普通命中
                            bool hit = false;
                            for (int i = 0; i < spines.Count; i++)
                            {
                                if (spines[i].IsHidden) continue;
                                if (!spines[i].GetCurrentBounds().Contains(src)) continue;

                                hit = true;

                                // 如果点到了没被选中的东西, 则清空原先选中的, 改为只选中这一次点的
                                if (!SpineListView.SelectedIndices.Contains(i))
                                {
                                    SpineListView.SelectedIndices.Clear();
                                    SpineListView.SelectedIndices.Add(i);
                                }
                                break;
                            }

                            // 如果点了空白的地方, 就清空选中列表
                            if (!hit) SpineListView.SelectedIndices.Clear();
                        }
                        else
                        {
                            // 按下 Ctrl 的情况就执行多选, 并且点空白处也不会清空选中
                            for (int i = 0; i < spines.Count; i++)
                            {
                                if (spines[i].IsHidden) continue;
                                if (!spines[i].GetCurrentBounds().Contains(src)) continue;

                                SpineListView.SelectedIndices.Add(i);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void panel_Render_MouseMove(object sender, MouseEventArgs e)
        {
            if (renderWindow is null) return;

            if (draggingSrc is null) return;

            var src = (SFML.System.Vector2f)draggingSrc;
            var dst = renderWindow.MapPixelToCoords(new(e.X, e.Y));
            var _delta = dst - src;
            var delta = new SizeF(_delta.X, _delta.Y);

            if ((e.Button & MouseButtons.Right) != 0)
            {
                Center -= delta;
            }
            else if ((e.Button & MouseButtons.Left) != 0)
            {
                if (SpineListView is not null)
                {
                    lock (SpineListView.Spines)
                    {
                        var spines = SpineListView.Spines;
                        foreach (int i in SpineListView.SelectedIndices)
                        {
                            if (spines[i].IsHidden) continue;
                            spines[i].Position += delta;
                        }
                    }
                }
                draggingSrc = dst;
            }
        }

        private void panel_Render_MouseUp(object sender, MouseEventArgs e)
        {
            // 右键高优先级, 结束画面拖动模式
            if ((e.Button & MouseButtons.Right) != 0)
            {
                SpineListView?.SpinePropertyGrid?.Refresh();

                draggingSrc = null;
                Cursor = Cursors.Default;
                PropertyGrid?.Refresh();
            }
            // 按下了左键并且右键是松开的
            else if ((e.Button & MouseButtons.Left) != 0 && (MouseButtons & MouseButtons.Right) == 0)
            {
                draggingSrc = null;
                SpineListView?.SpinePropertyGrid?.Refresh();
            }
        }

        private void panel_Render_MouseWheel(object sender, MouseEventArgs e)
        {
            var factor = (e.Delta > 0 ? 1.1f : 0.9f);
            if ((ModifierKeys & Keys.Control) == 0)
            {
                Zoom *= factor;
                PropertyGrid?.Refresh();
            }
            else
            {
                if (SpineListView is not null)
                {
                    lock (SpineListView.Spines)
                    {
                        var spines = SpineListView.Spines;
                        foreach (int i in SpineListView.SelectedIndices)
                        {
                            if (spines[i].IsHidden) continue;
                            spines[i].Scale *= factor;
                        }
                    }
                    SpineListView.SpinePropertyGrid?.Refresh();
                }
            }
        }

        private void button_Stop_Click(object sender, EventArgs e)
        {
            IsUpdating = false;
            if (SpineListView is not null)
            {
                lock (SpineListView.Spines)
                {
                    foreach (var spine in SpineListView.Spines)
                        spine.ResetAnimationsTime();
                }
            }
        }

        private void button_Restart_Click(object sender, EventArgs e)
        {
            if (SpineListView is not null)
            {
                lock (SpineListView.Spines)
                {
                    foreach (var spine in SpineListView.Spines)
                        spine.ResetAnimationsTime();
                }
            }
            IsUpdating = true;
        }

        private void button_Start_Click(object sender, EventArgs e)
        {
            IsUpdating = !IsUpdating;
        }

        private void button_ForwardStep_Click(object sender, EventArgs e)
        {
            lock (_forwardDeltaLock)
            {
                if (maxFps > 0)
                    forwardDelta += 1f / maxFps;
                else
                    forwardDelta += 0.001f;
            }
        }

        private void button_ForwardFast_Click(object sender, EventArgs e)
        {
            lock (_forwardDeltaLock)
            {
                if (maxFps > 0)
                    forwardDelta += 10f / maxFps;
                else
                    forwardDelta += 0.01f;
            }
        }

        private void button_FullScreen_Click(object sender, EventArgs e)
        {
            var screenBounds = Screen.FromControl(this).Bounds;
            Resolution = screenBounds.Size;
            PropertyGrid?.Refresh();

            // PerfMonitorV2 模式下, 位置和大小需要分开设置
            // 因为目标位置的 DPI 可能发生变化, 因此在 WM_POSITIONCHANGED 之后会收到 WM_DPICHANGED
            // 进而导致一次额外的 WM_SIZE 消息, 其大小是 DPI 修改前的大小, 这个消息在此次设置之后发生
            // 因此如果同时设置位置和大小则大小可能设置失败
            spinePreviewFullScreenForm.Location = screenBounds.Location;
            spinePreviewFullScreenForm.Size = screenBounds.Size;
            spinePreviewFullScreenForm.Controls.Add(panel_RenderContainer);
            spinePreviewFullScreenForm.Show();
        }

        private void spinePreviewFullScreenForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                spinePreviewFullScreenForm.Hide();
                panel_ViewContainer.Controls.Add(panel_RenderContainer);
            }
        }

        private void spinePreviewFullScreenForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = e.CloseReason == CloseReason.UserClosing;
        }

        private void wallpaperForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = e.CloseReason == CloseReason.UserClosing;
        }

        //public void ClickStopButton() => button_Stop_Click(button_Stop, EventArgs.Empty);
        //public void ClickRestartButton() => button_Restart_Click(button_Restart, EventArgs.Empty);
        //public void ClickStartButton() => button_Start_Click(button_Start, EventArgs.Empty);
        //public void ClickForwardStepButton() => button_ForwardStep_Click(button_ForwardStep, EventArgs.Empty);
        //public void ClickForwardFastButton() => button_ForwardFast_Click(button_ForwardFast, EventArgs.Empty);
    }

    /// <summary>
    /// 用于在 PropertyGrid 上显示 <see cref="SpinePreviewPanel"/> 属性的包装类, 提供用户操作接口
    /// </summary>
    public class SpinePreviewPanelProperty(SpinePreviewPanel previewPanel)
    {
        [Browsable(false)]
        public SpinePreviewPanel PreviewPanel { get; } = previewPanel;

        [RefreshProperties(RefreshProperties.All)]
        [TypeConverter(typeof(ResolutionConverter))]
        [LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
        [LocalizedDisplayName(typeof(Properties.Resources), "displayResolution")]
        public Size Resolution { get => PreviewPanel.Resolution; set => PreviewPanel.Resolution = value; }

        [TypeConverter(typeof(PointFConverter))]
		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayCenter")]
		public PointF Center { get => PreviewPanel.Center; set => PreviewPanel.Center = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayZoom")]
		public float Zoom { get => PreviewPanel.Zoom; set => PreviewPanel.Zoom = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayRotation")]
		public float Rotation { get => PreviewPanel.Rotation; set => PreviewPanel.Rotation = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayFlipHorizontal")]
		public bool FlipX { get => PreviewPanel.FlipX; set => PreviewPanel.FlipX = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayFlipVertical")]
		public bool FlipY { get => PreviewPanel.FlipY; set => PreviewPanel.FlipY = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryCustom")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayRenderSelected")]
		public bool RenderSelectedOnly { get => PreviewPanel.RenderSelectedOnly; set => PreviewPanel.RenderSelectedOnly = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryExport")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayShowAxis")]
		public bool ShowAxis { get => PreviewPanel.ShowAxis; set => PreviewPanel.ShowAxis = value; }

		[LocalizedCategory(typeof(Properties.Resources), "categoryExport")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayMaximumFrameRate")]
		public uint MaxFps { get => PreviewPanel.MaxFps; set => PreviewPanel.MaxFps = value; }

        [Editor(typeof(SFMLColorEditor), typeof(UITypeEditor))]
        [TypeConverter(typeof(SFMLColorConverter))]
		[LocalizedCategory(typeof(Properties.Resources), "categoryExport")]
		[LocalizedDisplayName(typeof(Properties.Resources), "displayBackgroundColor")]
		public SFML.Graphics.Color BackgroundColor { get => PreviewPanel.BackgroundColor; set => PreviewPanel.BackgroundColor = value; }
    }
}
