using System;
using System.Collections.Generic;
using System.Text;
using CPF.Input;
using CPF.Drawing;
using CPF.Styling;
using System.Linq;
using CPF.Shapes;
using System.ComponentModel;

namespace CPF.Controls
{
    /// <summary>
    /// 表示一个控件，该控件可让用户通过沿 Thumb 移动 Track 控件从一个值范围中进行选择。
    /// </summary>
    [Description("表示一个控件，该控件可让用户通过沿 Thumb 移动 Track 控件从一个值范围中进行选择。"), Browsable(true)]
    public class Slider : RangeBase
    {
        public Slider()
        {
            DecreaseLargeChanged = () =>
            {
                Value -= LargeChange;
            };
            IncreaseLargeChanged = () =>
            {
                Value += LargeChange;
            };
            DecreaseSmallChange = () => { Value -= SmallChange; };
            IncreaseSmallChange = () => { Value += SmallChange; };
        }


        protected override void InitializeComponent()
        {
            //Background = "#f00";
            Children.Add(new TickBar
            {
                PresenterFor = this,
                Name = "TopTick",
                Height = 8,
                MarginLeft = 5,
                MarginRight = 5,
                MarginTop = 0,
                Fill = "229,229,229",
                Bindings =
                {
                    { nameof(TickBar.Maximum),nameof(Maximum),this},
                    { nameof(TickBar.Minimum),nameof(Minimum),this},
                    { nameof(TickBar.IsDirectionReversed),nameof(IsDirectionReversed),this},
                    { nameof(TickBar.TickFrequency),nameof(TickFrequency),this},
                    { nameof(TickBar.Ticks),nameof(Ticks),this},
                    { nameof(TickBar.Visibility),nameof(TickPlacement),this,BindingMode.OneWay,a=>(TickPlacement)a== TickPlacement.Both||(TickPlacement)a== TickPlacement.TopLeft?Visibility.Visible:Visibility.Collapsed}
                }
            });
            Triggers.Add(new Trigger
            {
                Property = nameof(Orientation),
                PropertyConditions = a => (Orientation)a == Orientation.Vertical,
                TargetRelation = Relation.Me.Children(a => a.Name == "TopTick" && a.PresenterFor == this),
                Setters =
                {
                    {nameof(MarginBottom),5 },
                    {nameof(MarginTop),5 },
                    {nameof(MarginLeft),0 },
                    {nameof(MarginRight),FloatField.Auto },
                    {nameof(Height),FloatField.Auto },
                    {nameof(Width),8 },
                    {nameof(TickBar.Placement),TickBarPlacement.Left },
                }
            });
            Children.Add(new TickBar
            {
                PresenterFor = this,
                Name = "BottomTick",
                Height = 8,
                MarginLeft = 5,
                MarginRight = 5,
                MarginBottom = 0,
                Fill = "229,229,229",
                Placement = TickBarPlacement.Bottom,
                Bindings =
                {
                    { nameof(TickBar.Maximum),nameof(Maximum),this},
                    { nameof(TickBar.Minimum),nameof(Minimum),this},
                    { nameof(TickBar.IsDirectionReversed),nameof(IsDirectionReversed),this},
                    { nameof(TickBar.TickFrequency),nameof(TickFrequency),this},
                    { nameof(TickBar.Ticks),nameof(Ticks),this},
                    { nameof(TickBar.Visibility),nameof(TickPlacement),this,BindingMode.OneWay,a=>(TickPlacement)a== TickPlacement.Both||(TickPlacement)a== TickPlacement.BottomRight?Visibility.Visible:Visibility.Collapsed}
                }
            });

            Triggers.Add(new Trigger
            {
                Property = nameof(Orientation),
                PropertyConditions = a => (Orientation)a == Orientation.Vertical,
                TargetRelation = Relation.Me.Children(a => a.Name == "BottomTick" && a.PresenterFor == this),
                Setters =
                {
                    {nameof(MarginBottom),5 },
                    {nameof(MarginTop),5 },
                    {nameof(MarginLeft),FloatField.Auto },
                    {nameof(MarginRight),0 },
                    {nameof(Height),FloatField.Auto },
                    {nameof(Width),8 },
                    {nameof(TickBar.Placement),TickBarPlacement.Right },
                }
            });
            Children.Add(new Border
            {
                Name = "TrackBackground",
                PresenterFor = this,
                MarginRight = 5,
                MarginLeft = 5,
                Height = 4,
                BorderFill = "187,187,187",
                Background = "231,234,234",
            });

            Triggers.Add(new Trigger
            {
                Property = nameof(Orientation),
                PropertyConditions = a => (Orientation)a == Orientation.Vertical,
                TargetRelation = Relation.Me.Children(a => a.Name == "TrackBackground" && a.PresenterFor == this),
                Setters =
                {
                    {nameof(MarginBottom),5 },
                    {nameof(MarginTop),5 },
                    {nameof(MarginLeft),FloatField.Auto },
                    {nameof(MarginRight),FloatField.Auto },
                    {nameof(Height),FloatField.Auto },
                    {nameof(Width),4 },
                }
            });
            Children.Add(new Track
            {
                PresenterFor = this,
                Name = "PART_Track",
                Height = "100%",
                Width = "100%",
                IsDirectionReversed = true,
                Thumb = new Thumb
                {
                    Width = "100%",
                    Height = "10",
                    BorderFill = "187,187,187",
                    BorderStroke = new Stroke(1),
                    Bindings =
                    {
                        { nameof(Width),nameof(Orientation),this,BindingMode.OneWay,a=>((Orientation)a)==Orientation.Horizontal?(FloatField)10:16 },
                        { nameof(Height),nameof(Orientation),this,BindingMode.OneWay,a=>((Orientation)a)==Orientation.Horizontal?(FloatField)16:10 },
                    },
                    Triggers =
                    {
                        new Trigger { Property = nameof(IsMouseOver), Setters = { { "Background", "190,230,253" } } },
                        new Trigger { Property = nameof(Thumb.IsDragging), Setters = { { "Background", "186,209,226" } } }
                    },
                    Commands =
                    {
                        { nameof(Thumb.DragStarted), nameof(OnThumbDragStarted), this,CommandParameter.EventSender, CommandParameter.EventArgs },
                        { nameof(Thumb.DragCompleted), nameof(OnThumbDragCompleted), this,CommandParameter.EventSender, CommandParameter.EventArgs },
                        { nameof(Thumb.DragDelta), nameof(OnThumbDragDelta), this,CommandParameter.EventSender, CommandParameter.EventArgs },
                    }
                },
                IncreaseRepeatButton = new RepeatButton
                {
                    Name = "increaseRepeatButton",
                    Width = "100%",
                    Height = "100%",
                    Commands = { { nameof(RepeatButton.Click), nameof(CommandIncreaseLargeChanged), this } },
                    Bindings =
                    {
                        {nameof(RepeatButton.Delay),nameof(Delay),this },
                        {nameof(RepeatButton.Interval),nameof(Interval),this },
                    }
                },
                DecreaseRepeatButton = new RepeatButton
                {
                    Name = "decreaseRepeatButton",
                    Width = "100%",
                    Height = "100%",
                    Commands = { { nameof(RepeatButton.Click), nameof(CommandDecreaseLargeChanged), this } },
                    Bindings =
                    {
                        {nameof(RepeatButton.Delay),nameof(Delay),this },
                        {nameof(RepeatButton.Interval),nameof(Interval),this },
                    }
                },
                Bindings =
                {
                    { nameof(Track.Orientation), nameof(Orientation),1 },
                    { nameof(Track.Maximum),nameof(Maximum),1},
                    { nameof(Track.Minimum),nameof(Minimum),1},
                    { nameof(Track.Value),nameof(Value),1,BindingMode.TwoWay},
                    { nameof(Track.IsDirectionReversed),nameof(IsDirectionReversed),1},
                }
            });
        }

        protected override void OnInitialized()
        {
            base.OnInitialized();
            this.Track = FindPresenter<Track>().FirstOrDefault(a => a.Name == "PART_Track");
        }



        /// <summary>
        /// 减
        /// </summary>
        public Action DecreaseLargeChanged;

        protected void CommandDecreaseLargeChanged()
        {
            DecreaseLargeChanged?.Invoke();
        }
        /// <summary>
        /// 加
        /// </summary>
        public Action IncreaseLargeChanged;
        protected void CommandIncreaseLargeChanged()
        {
            IncreaseLargeChanged?.Invoke();
        }
        /// <summary>
        /// 减
        /// </summary>
        public Action DecreaseSmallChange;
        protected void CommandDecreaseSmallChange()
        {
            DecreaseSmallChange?.Invoke();
        }
        /// <summary>
        /// 加
        /// </summary>
        public Action IncreaseSmallChange;
        protected void CommandIncreaseSmallChange()
        {
            IncreaseSmallChange?.Invoke();
        }
        /// <summary>
        /// 布局方向
        /// </summary>
        [Description("布局方向")]
        public Orientation Orientation
        {
            get { return (Orientation)GetValue(); }
            set { SetValue(value); }
        }
        /// <summary>
        /// 获取或设置与 Track 的 Slider 相关的刻度线的位置。
        /// </summary>
        [PropertyMetadata(TickPlacement.None)]
        [Description("获取或设置与 Track 的 Slider 相关的刻度线的位置。")]
        public TickPlacement TickPlacement
        {
            get
            {
                return (TickPlacement)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }

        /// <summary>
        /// 如果增加值的方向向左（对于水平滑块）或向下（对于垂直滑块），则为 true；否则为 false。 默认值为 false。
        /// </summary>
        [PropertyMetadata(false)]
        [Description("如果增加值的方向向左（对于水平滑块）或向下（对于垂直滑块），则为 true；否则为 false。 默认值为 false。")]
        public bool IsDirectionReversed
        {
            get
            {
                return (bool)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 获取或设置在按下 RepeatButton 之后等待执行用于移动 Thumb 的命令（如 DecreaseLarge 命令）的时间（以毫秒为单位）。
        /// </summary>
        [PropertyMetadata(250)]
        [Description("获取或设置在按下 RepeatButton 之后等待执行用于移动 Thumb 的命令（如 DecreaseLarge 命令）的时间（以毫秒为单位）。")]
        public int Delay
        {
            get
            {
                return (int)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 获取或设置当用户单击 RepeatButton 的 Slider 时增加或减少命令之间的时间量（以毫秒为单位）
        /// </summary>
        [PropertyMetadata(100)]
        [Description("获取或设置当用户单击 RepeatButton 的 Slider 时增加或减少命令之间的时间量（以毫秒为单位）")]
        public int Interval
        {
            get
            {
                return (int)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 获取或设置一个值，该值指示 Slider 是否自动将 Thumb 移动到最近的刻度线
        /// </summary>
        [PropertyMetadata(true)]
        [Description("获取或设置一个值，该值指示 Slider 是否自动将 Thumb 移动到最近的刻度线")]
        public bool IsSnapToTickEnabled
        {
            get
            {
                return (bool)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 刻度线之间的距离。 默认值为 (1.0)。
        /// </summary>
        [PropertyMetadata(1f)]
        [Description(" 刻度线之间的距离。 默认值为 (1.0)。")]
        public float TickFrequency
        {
            get
            {
                return (float)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 获取或设置刻度线的位置。
        /// </summary>
        [Description("获取或设置刻度线的位置。")]
        public Collection<float> Ticks
        {
            get
            {
                return (Collection<float>)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }
        /// <summary>
        /// 获取或设置一个值，该值指示是否立即将 Slider 的 Thumb 移动到在鼠标指针悬停在 Slider 轨道的上方时鼠标单击的位置。
        /// </summary>
        //[PropertyMetadata(true)]
        [Description(" 获取或设置一个值，该值指示是否立即将 Slider 的 Thumb 移动到在鼠标指针悬停在 Slider 轨道的上方时鼠标单击的位置。")]
        public bool IsMoveToPointEnabled
        {
            get
            {
                return (bool)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }


        /// <summary>
        /// Gets or sets reference to Slider's Track element.
        /// </summary>
        [NotCpfProperty]
        internal Track Track
        {
            get;
            set;
        }

        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            if (IsMoveToPointEnabled && Track != null && Track.Thumb != null && !Track.Thumb.IsMouseOver)
            {
                // Move Thumb to the Mouse location

                Point pt = e.MouseDevice.GetPosition(Track);
                var newValue = Track.ValueFromPoint(pt);
                if (FloatUtil.IsFloatFinite(newValue))
                {
                    UpdateValue(newValue);
                }
                e.Handled = true;
            }
            base.OnPreviewMouseDown(e);
        }


        protected virtual void OnThumbDragStarted(object sender, DragStartedEventArgs e)
        {
            //// Show AutoToolTip if needed.
            //Thumb thumb = e.OriginalSource as Thumb;

            //if ((thumb == null) || (this.AutoToolTipPlacement == Primitives.AutoToolTipPlacement.None))
            //{
            //    return;
            //}

            //// Save original tooltip
            //_thumbOriginalToolTip = thumb.ToolTip;

            //if (_autoToolTip == null)
            //{
            //    _autoToolTip = new ToolTip();
            //    _autoToolTip.Placement = PlacementMode.Custom;
            //    _autoToolTip.PlacementTarget = thumb;
            //    _autoToolTip.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(this.AutoToolTipCustomPlacementCallback);
            //}

            //thumb.ToolTip = _autoToolTip;
            //_autoToolTip.Content = GetAutoToolTipNumber();
            //_autoToolTip.IsOpen = true;
            //((Popup)_autoToolTip.Parent).Reposition();
        }

        /// <summary>
        /// Called when user dragging the Thumb.
        /// This function can be override to customize the way Slider handles Thumb movement.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
        {
            Thumb thumb = e.OriginalSource as Thumb;
            // Convert to Track's co-ordinate
            if (Track != null && thumb == Track.Thumb)
            {

                float newValue = (float)Value + Track.ValueFromDistance(e.HorizontalChange, e.VerticalChange);
                if (FloatUtil.IsFloatFinite(newValue))
                {
                    UpdateValue(newValue);
                }

                //// Show AutoToolTip if needed
                //if (this.AutoToolTipPlacement != Primitives.AutoToolTipPlacement.None)
                //{
                //    if (_autoToolTip == null)
                //    {
                //        _autoToolTip = new ToolTip();
                //    }

                //    _autoToolTip.Content = GetAutoToolTipNumber();

                //    if (thumb.ToolTip != _autoToolTip)
                //    {
                //        thumb.ToolTip = _autoToolTip;
                //    }

                //    if (!_autoToolTip.IsOpen)
                //    {
                //        _autoToolTip.IsOpen = true;
                //    }
                //    ((Popup)_autoToolTip.Parent).Reposition();
                //}
            }
        }

        protected virtual void OnThumbDragCompleted(object sender, DragCompletedEventArgs e)
        {
            //// Show AutoToolTip if needed.
            //Thumb thumb = e.OriginalSource as Thumb;

            //if ((thumb == null) || (this.AutoToolTipPlacement == Primitives.AutoToolTipPlacement.None))
            //{
            //    return;
            //}

            //if (_autoToolTip != null)
            //{
            //    _autoToolTip.IsOpen = false;
            //}

            //thumb.ToolTip = _thumbOriginalToolTip;
        }

        /// <summary>
        /// Helper function for value update.
        /// This function will also snap the value to tick, if IsSnapToTickEnabled is true.
        /// </summary>
        /// <param name="value"></param>
        private void UpdateValue(float value)
        {
            float snappedValue = SnapToTick(value);

            if (snappedValue != Value)
            {
                Value = Math.Max(this.Minimum, Math.Min(this.Maximum, snappedValue));
            }
        }

        /// <summary>
        /// Snap the input 'value' to the closest tick.
        /// If input value is exactly in the middle of 2 surrounding ticks, it will be snapped to the tick that has greater value.
        /// </summary>
        /// <param name="value">Value that want to snap to closest Tick.</param>
        /// <returns>Snapped value if IsSnapToTickEnabled is 'true'. Otherwise, returns un-snaped value.</returns>
        private float SnapToTick(float value)
        {
            if (IsSnapToTickEnabled)
            {
                var previous = Minimum;
                var next = Maximum;

                // This property is rarely set so let's try to avoid the GetValue
                // caching of the mutable default value
                var ticks = Ticks;
                //bool hasModifiers;
                //if (GetValueSource(TicksProperty, null, out hasModifiers)
                //    != BaseValueSourceInternal.Default || hasModifiers)
                //{
                //    ticks = Ticks;
                //}

                // If ticks collection is available, use it.
                // Note that ticks may be unsorted.
                if ((ticks != null) && (ticks.Count > 0))
                {
                    for (int i = 0; i < ticks.Count; i++)
                    {
                        var tick = ticks[i];
                        if (FloatUtil.AreClose(tick, value))
                        {
                            return value;
                        }

                        if (FloatUtil.LessThan(tick, value) && FloatUtil.GreaterThan(tick, (float)previous))
                        {
                            previous = tick;
                        }
                        else if (FloatUtil.GreaterThan(tick, value) && FloatUtil.LessThan(tick, (float)next))
                        {
                            next = tick;
                        }
                    }
                }
                else if (FloatUtil.GreaterThan(TickFrequency, 0f))
                {
                    previous = (float)(Minimum + (Math.Round(((value - Minimum) / TickFrequency)) * TickFrequency));
                    next = Math.Min(Maximum, previous + TickFrequency);
                }

                // Choose the closest value between previous and next. If tie, snap to 'next'.
                value = FloatUtil.GreaterThanOrClose((float)value, (float)(previous + next) * 0.5f) ? (float)next : (float)previous;
            }

            return value;
        }

        // Sets Value = SnapToTick(value+direction), unless the result of SnapToTick is Value,
        // then it searches for the next tick greater(if direction is positive) than value
        // and sets Value to that tick
        private void MoveToNextTick(float direction)
        {
            if (direction != 0.0)
            {
                var value = this.Value;

                // Find the next value by snapping
                var next = SnapToTick(Math.Max((float)this.Minimum, Math.Min((float)this.Maximum, (float)value + direction)));

                bool greaterThan = direction > 0; //search for the next tick greater than value?

                // If the snapping brought us back to value, find the next tick point
                if (next == value
                    && !(greaterThan && value == Maximum)  // Stop if searching up if already at Max
                    && !(!greaterThan && value == Minimum)) // Stop if searching down if already at Min
                {
                    // This property is rarely set so let's try to avoid the GetValue
                    // caching of the mutable default value
                    //DoubleCollection ticks = null;
                    //bool hasModifiers;
                    //if (GetValueSource(TicksProperty, null, out hasModifiers)
                    //    != BaseValueSourceInternal.Default || hasModifiers)
                    //{
                    var ticks = Ticks;
                    //}

                    // If ticks collection is available, use it.
                    // Note that ticks may be unsorted.
                    if ((ticks != null) && (ticks.Count > 0))
                    {
                        for (int i = 0; i < ticks.Count; i++)
                        {
                            var tick = ticks[i];

                            // Find the smallest tick greater than value or the largest tick less than value
                            if ((greaterThan && FloatUtil.GreaterThan(tick, (float)value) && (FloatUtil.LessThan(tick, next) || next == value))
                             || (!greaterThan && FloatUtil.LessThan(tick, (float)value) && (FloatUtil.GreaterThan(tick, next) || next == value)))
                            {
                                next = tick;
                            }
                        }
                    }
                    else if (FloatUtil.GreaterThan(TickFrequency, 0f))
                    {
                        // Find the current tick we are at
                        var tickNumber = (float)Math.Round((value - Minimum) / TickFrequency);

                        if (greaterThan)
                            tickNumber += 1f;
                        else
                            tickNumber -= 1f;

                        next = (float)Minimum + tickNumber * TickFrequency;
                    }
                }


                // Update if we've found a better value
                if (next != value)
                {
                    this.Value = next;
                }
            }
        }

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            if (!IsKeyboardFocusWithin)
            {
                e.Handled = Focus() || e.Handled;
            }
            base.OnMouseDown(e);
        }


        /// <summary>
        /// Perform arrangement of slider's children
        /// </summary>
        /// <param name="finalSize"></param>
        protected override Size ArrangeOverride(in Size finalSize)
        {
            Size size = base.ArrangeOverride(finalSize);

            UpdateSelectionRangeElementPositionAndSize();

            return size;
        }
        [PropertyChanged(nameof(Value))]
        void OnValueChanged(object newValue, object oldValue, PropertyMetadataAttribute attribute)
        {
            UpdateSelectionRangeElementPositionAndSize();
        }

        /// <summary>
        /// Resize and resposition the SelectionRangeElement.
        /// </summary>
        private void UpdateSelectionRangeElementPositionAndSize()
        {
            //Size trackSize = new Size(0f, 0f);
            //Size thumbSize = new Size(0f, 0f);

            //if (Track == null || FloatField.LessThan(SelectionEnd, SelectionStart))
            //{
            //    return;
            //}

            //trackSize = Track.ActualSize;
            //thumbSize = (Track.Thumb != null) ? Track.Thumb.ActualSize : new Size(0f, 0f);

            //float range = Maximum - Minimum;
            //float valueToSize;

            //FrameworkElement rangeElement = this.SelectionRangeElement as FrameworkElement;

            //if (rangeElement == null)
            //{
            //    return;
            //}

            //if (Orientation == Orientation.Horizontal)
            //{
            //    // Calculate part size for HorizontalSlider
            //    if (DoubleUtil.AreClose(range, 0d) || (DoubleUtil.AreClose(trackSize.Width, thumbSize.Width)))
            //    {
            //        valueToSize = 0d;
            //    }
            //    else
            //    {
            //        valueToSize = Math.Max(0.0, (trackSize.Width - thumbSize.Width) / range);
            //    }

            //    rangeElement.Width = ((SelectionEnd - SelectionStart) * valueToSize);
            //    if (IsDirectionReversed)
            //    {
            //        Canvas.SetLeft(rangeElement, (thumbSize.Width * 0.5) + Math.Max(Maximum - SelectionEnd, 0) * valueToSize);
            //    }
            //    else
            //    {
            //        Canvas.SetLeft(rangeElement, (thumbSize.Width * 0.5) + Math.Max(SelectionStart - Minimum, 0) * valueToSize);
            //    }
            //}
            //else
            //{
            //    // Calculate part size for VerticalSlider
            //    if (DoubleUtil.AreClose(range, 0d) || (DoubleUtil.AreClose(trackSize.Height, thumbSize.Height)))
            //    {
            //        valueToSize = 0d;
            //    }
            //    else
            //    {
            //        valueToSize = Math.Max(0.0, (trackSize.Height - thumbSize.Height) / range);
            //    }

            //    rangeElement.Height = ((SelectionEnd - SelectionStart) * valueToSize);
            //    if (IsDirectionReversed)
            //    {
            //        Canvas.SetTop(rangeElement, (thumbSize.Height * 0.5) + Math.Max(SelectionStart - Minimum, 0) * valueToSize);
            //    }
            //    else
            //    {
            //        Canvas.SetTop(rangeElement, (thumbSize.Height * 0.5) + Math.Max(Maximum - SelectionEnd, 0) * valueToSize);
            //    }
            //}
        }


        protected override void OnOverrideMetadata(OverrideMetadata overridePropertys)
        {
            base.OnOverrideMetadata(overridePropertys);
            overridePropertys.Override(nameof(Maximum), new PropertyMetadataAttribute(10d));
            overridePropertys.Override(nameof(SmallChange), new PropertyMetadataAttribute(1d));
            overridePropertys.Override(nameof(LargeChange), new PropertyMetadataAttribute(2d));
        }
    }

    /// <summary>
    /// Placement options for Slider's Tickbar
    /// </summary>
    public enum TickPlacement : byte
    {
        /// <summary>
        /// No TickMark
        /// </summary>
        None,
        /// <summary>
        /// Show TickMark above the Track (for HorizontalSlider), or left of the Track (for VerticalSlider)
        /// </summary>
        TopLeft,
        /// <summary>
        /// Show TickMark below the Track (for HorizontalSlider), or right of the Track (for VerticalSlider)
        /// </summary>
        BottomRight,
        /// <summary>
        /// Show TickMark on both side of the Track
        /// </summary>
        Both,

        // NOTE: if you add or remove any values in this enum, be sure to update Slider.IsValidTickPlacement()    
    };
}
