Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Windows.Forms
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Composition
Imports Nexamas.UI.General
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Motion
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Official Nexamas UI slider input for bounded numeric selection. It owns the
    ''' premium track/thumb/tick/value-label visual route only. Binding, validation,
    ''' filtering, persistence, analytics, and domain-specific range semantics remain
    ''' outside this control.
    ''' </summary>
    Public NotInheritable Class MASSlider
        Inherits Nexamas.UI.Controls.MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract

#Region "Fields"

        Private Shared ReadOnly _contract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASSlider))

        Private _minimum As Double = SliderTokens.DefaultMinimum
        Private _maximum As Double = SliderTokens.DefaultMaximum
        Private _value As Double = SliderTokens.DefaultValue
        Private _step As Double = SliderTokens.DefaultStep
        Private _tickFrequency As Double = SliderTokens.DefaultTickFrequency
        Private _showTicks As Boolean = True
        Private _showValueLabel As Boolean
        Private _hoverThumb As Boolean
        Private _pressedThumb As Boolean
        Private _dragging As Boolean
        Private _valueMotionRunner As MASMotionTimelineRunner
        Private _visualValue As Double = SliderTokens.DefaultValue
        Private _hasVisualValueOverride As Boolean
        Private _lastTrackRect As SKRect = SKRect.Empty
        Private _lastThumbRect As SKRect = SKRect.Empty

#End Region

#Region "Constructor / Factory"

        Public Sub New()
            MyBase.New()
        End Sub

        Public Shared Function Create(Optional minimum As Double = SliderTokens.DefaultMinimum,
                                      Optional maximum As Double = SliderTokens.DefaultMaximum,
                                      Optional value As Double = SliderTokens.DefaultValue) As MASSlider
            Dim control As New MASSlider()
            control.SetRangeInternal(minimum, maximum, False)
            control.SetValueInternal(value, False)
            Return control
        End Function

#End Region

#Region "Public API"

        Public Event ValueChanged As EventHandler
        Public Event RangeChanged As EventHandler

        Public Property Minimum As Double
            Get
                Return _minimum
            End Get
            Set(value As Double)
                SetRangeInternal(value, _maximum, True)
            End Set
        End Property

        Public Property Maximum As Double
            Get
                Return _maximum
            End Get
            Set(value As Double)
                SetRangeInternal(_minimum, value, True)
            End Set
        End Property

        Public Property Value As Double
            Get
                Return _value
            End Get
            Set(value As Double)
                SetValueInternal(value, True)
            End Set
        End Property

        Public Property [Step] As Double
            Get
                Return _step
            End Get
            Set(value As Double)
                Dim normalized As Double = MASSliderRangePolicy.NormalizeStep(value)
                If NearlyEqual(_step, normalized) Then Return
                _step = normalized
                SetValueInternal(_value, True)
                InvalidateVisual()
            End Set
        End Property

        Public Property TickFrequency As Double
            Get
                Return _tickFrequency
            End Get
            Set(value As Double)
                Dim normalized As Double = MASSliderRangePolicy.NormalizeStep(value)
                If NearlyEqual(_tickFrequency, normalized) Then Return
                _tickFrequency = normalized
                InvalidateVisual()
            End Set
        End Property

        Public Property ShowTicks As Boolean
            Get
                Return _showTicks
            End Get
            Set(value As Boolean)
                If _showTicks = value Then Return
                _showTicks = value
                InvalidateVisual()
            End Set
        End Property

        Public Property ShowValueLabel As Boolean
            Get
                Return _showValueLabel
            End Get
            Set(value As Boolean)
                If _showValueLabel = value Then Return
                _showValueLabel = value
                RequestSizeLayoutRefreshForSizeAffectingChange("MASSlider.ShowValueLabel")
                InvalidateVisual()
            End Set
        End Property

        Public Function WithRange(minimum As Double, maximum As Double) As MASSlider
            SetRangeInternal(minimum, maximum, True)
            Return Me
        End Function

        Public Function WithValue(value As Double) As MASSlider
            Value = value
            Return Me
        End Function

        Public Function WithStep(stepValue As Double) As MASSlider
            [Step] = stepValue
            Return Me
        End Function

        Public Function WithTicks(Optional tickFrequency As Double = SliderTokens.DefaultTickFrequency) As MASSlider
            ShowTicks = True
            TickFrequency = tickFrequency
            Return Me
        End Function

        Public Function WithoutTicks() As MASSlider
            ShowTicks = False
            Return Me
        End Function

        Public Function WithValueLabel(Optional visible As Boolean = True) As MASSlider
            ShowValueLabel = visible
            Return Me
        End Function

        Public Function WithoutValueLabel() As MASSlider
            ShowValueLabel = False
            Return Me
        End Function

        Public Shadows Function WithSize(sizeIntent As MASSize) As MASSlider
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function

#End Region

#Region "Layout"

        Friend Function GetPreferredLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetPreferredLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).DesiredSize
        End Function

        Friend Function GetMinLayoutSize(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutParticipant.GetMinLayoutSize
            Return MeasureIntrinsicSize(CreateSizeContext(context), SizeIntent).MinSize
        End Function

        Friend Function MeasureIntrinsicSize(context As MASSizeContext,
                                             intent As MASSize) As MASSizeResult Implements IMASIntrinsicSizeContract.MeasureIntrinsicSize
            Dim safeContext As MASSizeContext = MASIntrinsicControlSizeMetrics.EnsureContext(context)
            Dim height As Single = If(_showValueLabel, SliderTokens.HeightWithValueLabelDip, SliderTokens.HeightDip)
            Dim desired As New SKSize(SliderTokens.PreferredWidthDip, height)
            Dim minimum As New SKSize(SliderTokens.MinWidthDip, SliderTokens.HeightDip)
            Dim contentInset As New MASLayoutInset(SliderTokens.PaddingHorizontalDip,
                                                   SliderTokens.PaddingVerticalDip,
                                                   SliderTokens.PaddingHorizontalDip,
                                                   SliderTokens.PaddingVerticalDip)

            Return MASSizeResolver.FromMeasured(
                desiredSize:=desired,
                minSize:=minimum,
                maxSize:=New SKSize(SliderTokens.MaxWidthDip, height),
                intent:=intent,
                context:=safeContext,
                canGrowWidth:=True,
                canGrowHeight:=False,
                contentInset:=contentInset,
                visualOverflowInset:=MASLayoutInset.Empty,
                hitOverflowInset:=MASLayoutInset.Empty,
                isFallback:=False)
        End Function

        Private Shared Function CreateSizeContext(context As MASLayoutMeasureContext) As MASSizeContext
            If context Is Nothing Then Return MASIntrinsicControlSizeMetrics.EnsureContext(Nothing)
            Return context.ToSizeContext()
        End Function

#End Region

#Region "Rendering"

        Protected Overrides Sub Render(canvas As SKCanvas,
                                       ctx As MASThemeContext,
                                       pixelBounds As SKRect)
            If canvas Is Nothing OrElse ctx Is Nothing Then Return
            If pixelBounds.Width <= 1.0F OrElse pixelBounds.Height <= 1.0F Then Return

            _contract.AssertConsumable()

            Dim dpi As Single = PixelSnap.SafeDpi(ctx.Dpi)
            Dim bounds As SKRect = PixelSnap.SnapRect(pixelBounds, dpi)
            Dim content As New SKRect(bounds.Left + SliderTokens.PaddingHorizontalDip * dpi,
                                      bounds.Top + SliderTokens.PaddingVerticalDip * dpi,
                                      bounds.Right - SliderTokens.PaddingHorizontalDip * dpi,
                                      bounds.Bottom - SliderTokens.PaddingVerticalDip * dpi)
            If content.Width <= 1.0F OrElse content.Height <= 1.0F Then Return

            If _showValueLabel Then
                DrawValueLabel(canvas, ctx, New SKRect(content.Left, content.Top, content.Right, content.Top + SliderTokens.ValueLabelHeightDip * dpi), dpi)
                content.Top += (SliderTokens.ValueLabelHeightDip + 7.0F) * dpi
            End If

            Dim centerY As Single = content.Top + Math.Max(SliderTokens.ThumbPressedSizeDip * 0.5F * dpi,
                                                           (content.Height * 0.5F))
            Dim thumbRadius As Single = ResolveThumbSizeDip() * 0.5F * dpi
            Dim trackLeft As Single = content.Left + thumbRadius
            Dim trackRight As Single = content.Right - thumbRadius
            If trackRight <= trackLeft Then Return

            _lastTrackRect = New SKRect(trackLeft,
                                        centerY - SliderTokens.TrackHeightDip * 0.5F * dpi,
                                        trackRight,
                                        centerY + SliderTokens.TrackHeightDip * 0.5F * dpi)

            DrawTrack(canvas, ctx, _lastTrackRect, dpi)
            If _showTicks Then DrawTicks(canvas, ctx, _lastTrackRect, dpi)
            DrawThumb(canvas, ctx, _lastTrackRect, dpi)
            DrawFocusRing(canvas, ctx, _lastTrackRect, dpi)
        End Sub

        Private Sub DrawValueLabel(canvas As SKCanvas,
                                   ctx As MASThemeContext,
                                   bounds As SKRect,
                                   dpi As Single)
            TypographyTextPrimitives.DrawSingleLineText(
                canvas:=canvas,
                ctx:=ctx,
                text:=FormatValue(_value),
                bounds:=bounds,
                dpi:=dpi,
                style:=MASTypography.MASTextStyle.Small,
                color:=ResolvePrimaryTextColor(ctx).WithAlpha(If(Enabled, SliderTokens.TextAlpha, SliderTokens.DisabledAlpha)),
                align:=TypographyTextPrimitives.TextAlign.Center,
                drawShadow:=False)
        End Sub

        Private Sub DrawTrack(canvas As SKCanvas,
                              ctx As MASThemeContext,
                              track As SKRect,
                              dpi As Single)
            Dim radius As Single = PixelSnap.SafeRadius(SliderTokens.TrackRadiusDip * dpi)
            Dim inactiveColor As SKColor = ResolveMutedTextColor(ctx).WithAlpha(If(Enabled, SliderTokens.TrackInactiveAlpha, SliderTokens.DisabledAlpha))
            Dim activeColor As SKColor = ResolveAccentColor(ctx).WithAlpha(If(Enabled, SliderTokens.TrackActiveAlpha, SliderTokens.DisabledAlpha))

            Using paint As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Fill, .Color = inactiveColor}
                canvas.DrawRoundRect(track, radius, radius, paint)
            End Using

            Dim ratio As Single = ValueRatio(ResolveRenderValue())
            Dim active As SKRect
            If ResolveRightToLeft() Then
                active = New SKRect(track.Right - track.Width * ratio, track.Top, track.Right, track.Bottom)
            Else
                active = New SKRect(track.Left, track.Top, track.Left + track.Width * ratio, track.Bottom)
            End If

            If active.Width > 0.5F Then
                Using paint As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Fill, .Color = activeColor}
                    canvas.DrawRoundRect(PixelSnap.SnapRect(active, dpi), radius, radius, paint)
                End Using
            End If
        End Sub

        Private Sub DrawTicks(canvas As SKCanvas,
                              ctx As MASThemeContext,
                              track As SKRect,
                              dpi As Single)
            Dim frequency As Double = MASSliderRangePolicy.ResolveTickFrequency(_tickFrequency, _step)
            Dim tickCount As Integer = MASSliderRangePolicy.ResolveTickCount(_minimum, _maximum, frequency)
            If tickCount <= 0 Then Return

            Dim tickTop As Single = track.Bottom + 5.0F * dpi
            Dim tickBottom As Single = tickTop + SliderTokens.TickHeightDip * dpi
            Using paint As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Stroke, .StrokeWidth = Math.Max(1.0F, SliderTokens.TickWidthDip * dpi), .Color = ResolveMutedTextColor(ctx).WithAlpha(If(Enabled, SliderTokens.TickAlpha, SliderTokens.DisabledAlpha))}
                For i As Integer = 0 To tickCount
                    Dim value As Double = Math.Min(_maximum, _minimum + frequency * CDbl(i))
                    Dim x As Single = ValueToX(value, track)
                    canvas.DrawLine(x, tickTop, x, tickBottom, paint)
                Next
            End Using
        End Sub

        Private Sub DrawThumb(canvas As SKCanvas,
                              ctx As MASThemeContext,
                              track As SKRect,
                              dpi As Single)
            Dim size As Single = ResolveThumbSizeDip() * dpi
            Dim centerX As Single = ValueToX(ResolveRenderValue(), track)
            Dim centerY As Single = (track.Top + track.Bottom) * 0.5F
            _lastThumbRect = New SKRect(centerX - size * 0.5F, centerY - size * 0.5F, centerX + size * 0.5F, centerY + size * 0.5F)

            Dim fillAlpha As Byte = SliderTokens.ThumbFillAlpha
            If _pressedThumb OrElse _dragging Then
                fillAlpha = SliderTokens.ThumbPressedAlpha
            ElseIf _hoverThumb Then
                fillAlpha = SliderTokens.ThumbHoverAlpha
            End If

            Using paint As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Fill, .Color = ResolveAccentColor(ctx).WithAlpha(If(Enabled, fillAlpha, SliderTokens.DisabledAlpha))}
                canvas.DrawOval(_lastThumbRect, paint)
            End Using

            Using stroke As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Stroke, .StrokeWidth = Math.Max(1.0F, SliderTokens.ThumbStrokeDip * dpi), .Color = ResolveSurfaceColor(ctx).WithAlpha(SliderTokens.ThumbBorderAlpha)}
                canvas.DrawOval(_lastThumbRect, stroke)
            End Using
        End Sub

        Private Sub DrawFocusRing(canvas As SKCanvas,
                                  ctx As MASThemeContext,
                                  track As SKRect,
                                  dpi As Single)
            If Not HasKeyboardFocus Then Return
            Dim focus As SKRect = _lastThumbRect
            If focus.IsEmpty Then focus = New SKRect(track.Left, track.Top - 8.0F * dpi, track.Right, track.Bottom + 8.0F * dpi)
            focus.Inflate(3.0F * dpi, 3.0F * dpi)
            Using paint As New SKPaint With {.IsAntialias = True, .Style = SKPaintStyle.Stroke, .StrokeWidth = Math.Max(1.0F, SliderTokens.FocusStrokeDip * dpi), .Color = ResolveAccentColor(ctx).WithAlpha(SliderTokens.FocusAlpha)}
                canvas.DrawOval(focus, paint)
            End Using
        End Sub

#End Region

#Region "Input"

        Protected Overrides Sub OnMouseMove(ctx As MASThemeContext, ptPx As SKPoint)
            If Not Enabled Then Return
            If _dragging Then
                SetValueInternal(PointToValue(ptPx), True, animate:=False)
                Return
            End If

            Dim hover As Boolean = _lastThumbRect.Contains(ptPx.X, ptPx.Y)
            If _hoverThumb = hover Then Return
            _hoverThumb = hover
            InvalidateVisual()
        End Sub

        Protected Overrides Function OnMouseDown(ctx As MASThemeContext,
                                                 ptPx As SKPoint,
                                                 button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False
            If Not Enabled Then Return False
            RequestFocus()
            _pressedThumb = True
            _dragging = True
            StopValueMotion(syncToSemanticValue:=True)
            SetValueInternal(PointToValue(ptPx), True, animate:=False)
            InvalidateVisual()
            Return True
        End Function

        Protected Overrides Function OnMouseUp(ctx As MASThemeContext,
                                               ptPx As SKPoint,
                                               button As Integer) As Boolean
            If button <> CInt(MouseButtons.Left) Then Return False
            If _dragging Then SetValueInternal(PointToValue(ptPx), True, animate:=False)
            _pressedThumb = False
            _dragging = False
            _hoverThumb = _lastThumbRect.Contains(ptPx.X, ptPx.Y)
            InvalidateVisual()
            Return True
        End Function

        Protected Overrides Sub OnMouseLeave(ctx As MASThemeContext)
            If _dragging Then Return
            If Not _hoverThumb AndAlso Not _pressedThumb Then Return
            ResetPointerState()
            InvalidateVisual()
        End Sub

        Protected Overrides Sub OnMouseCancel(ctx As MASThemeContext)
            ResetPointerState()
            InvalidateVisual()
        End Sub

        Protected Overrides Sub OnHostLostFocus(ctx As MASThemeContext)
            ResetPointerState()
            StopValueMotion(syncToSemanticValue:=True)
            InvalidateVisual()
        End Sub

        Protected Overrides Function OnKeyDown(ctx As MASThemeContext,
                                               keyCode As Keys) As Boolean
            Dim delta As Double = ResolveKeyboardStep()
            Select Case keyCode
                Case Keys.Left
                    SetValueInternal(_value + If(ResolveRightToLeft(), delta, -delta), True, animate:=True)
                    Return True
                Case Keys.Right
                    SetValueInternal(_value + If(ResolveRightToLeft(), -delta, delta), True, animate:=True)
                    Return True
                Case Keys.Down
                    SetValueInternal(_value - delta, True, animate:=True)
                    Return True
                Case Keys.Up
                    SetValueInternal(_value + delta, True, animate:=True)
                    Return True
                Case Keys.PageDown
                    SetValueInternal(_value - MASSliderRangePolicy.ResolveKeyboardPageStep(_step, _minimum, _maximum), True, animate:=True)
                    Return True
                Case Keys.PageUp
                    SetValueInternal(_value + MASSliderRangePolicy.ResolveKeyboardPageStep(_step, _minimum, _maximum), True, animate:=True)
                    Return True
                Case Keys.Home
                    SetValueInternal(_minimum, True, animate:=True)
                    Return True
                Case Keys.End
                    SetValueInternal(_maximum, True, animate:=True)
                    Return True
            End Select
            Return False
        End Function

        Protected Overrides Function WantsKeyboardFocus() As Boolean
            Return Visible AndAlso Enabled
        End Function

        Protected Overrides Function WantsPointerFocus() As Boolean
            Return WantsKeyboardFocus()
        End Function

#End Region

#Region "Helpers"

        Private Sub SetRangeInternal(minimum As Double,
                                     maximum As Double,
                                     raiseEvents As Boolean)
            Dim safeMin As Double = minimum
            Dim safeMax As Double = maximum
            MASSliderRangePolicy.NormalizeRange(safeMin, safeMax)

            Dim changed As Boolean = Not NearlyEqual(_minimum, safeMin) OrElse Not NearlyEqual(_maximum, safeMax)
            If Not changed Then Return

            _minimum = safeMin
            _maximum = safeMax
            SetValueInternal(_value, False)
            StopValueMotion(syncToSemanticValue:=True)
            RequestSizeLayoutRefreshForSizeAffectingChange("MASSlider.Range")
            If raiseEvents Then RaiseRangeChangedSafe()
            InvalidateVisual()
        End Sub

        Private Sub SetValueInternal(candidate As Double,
                                     raiseEvents As Boolean,
                                     Optional animate As Boolean = False)
            Dim normalized As Double = NormalizeValue(candidate)
            If NearlyEqual(_value, normalized) Then Return

            Dim previousVisualValue As Double = ResolveRenderValue()
            _value = normalized

            If animate AndAlso Not _dragging Then
                StartValueMotion(previousVisualValue, normalized)
            Else
                StopValueMotion(syncToSemanticValue:=True)
            End If

            If raiseEvents Then RaiseValueChangedSafe()
            InvalidateVisual()
        End Sub

        Private Function NormalizeValue(candidate As Double) As Double
            Return MASSliderRangePolicy.NormalizeValue(candidate, _minimum, _maximum, _step)
        End Function

        Private Shared Function NearlyEqual(left As Double, right As Double) As Boolean
            Return Math.Abs(left - right) <= 0.0000001
        End Function

        Private Function ValueRatio(value As Double) As Single
            Dim span As Double = _maximum - _minimum
            If span <= SliderTokens.MinRangeSpan Then Return 0.0F
            Return CSng(Math.Max(0.0, Math.Min(1.0, (value - _minimum) / span)))
        End Function

        Private Function ValueToX(value As Double, track As SKRect) As Single
            Dim span As Double = _maximum - _minimum
            Dim ratio As Single = If(span <= SliderTokens.MinRangeSpan, 0.0F, CSng(Math.Max(0.0, Math.Min(1.0, (value - _minimum) / span))))
            If ResolveRightToLeft() Then Return track.Right - track.Width * ratio
            Return track.Left + track.Width * ratio
        End Function

        Private Function PointToValue(ptPx As SKPoint) As Double
            If _lastTrackRect.IsEmpty OrElse _lastTrackRect.Width <= 0.5F Then Return _value
            Dim ratio As Double = (CDbl(ptPx.X) - CDbl(_lastTrackRect.Left)) / CDbl(_lastTrackRect.Width)
            ratio = Math.Max(0.0, Math.Min(1.0, ratio))
            If ResolveRightToLeft() Then ratio = 1.0 - ratio
            Return _minimum + (_maximum - _minimum) * ratio
        End Function

        Private Function ResolveThumbSizeDip() As Single
            If _pressedThumb OrElse _dragging Then Return SliderTokens.ThumbPressedSizeDip
            Return SliderTokens.ThumbSizeDip
        End Function

        Private Function ResolveRenderValue() As Double
            If _hasVisualValueOverride Then
                Return NormalizeValue(_visualValue)
            End If

            Return _value
        End Function

        Private Sub StartValueMotion(fromValue As Double, toValue As Double)
            StopValueMotion(syncToSemanticValue:=False)

            fromValue = NormalizeValue(fromValue)
            toValue = NormalizeValue(toValue)
            _visualValue = fromValue
            _hasVisualValueOverride = True

            Dim fullDistance As Single = CSng(Math.Max(SliderTokens.MinRangeSpan, _maximum - _minimum))
            Dim plan As MASMotionTransitionPlan = MASMotionSystem.CreateDistanceScaledTransitionPlan(
                MASMotionTokenId.ValueScrub,
                CSng(fromValue),
                CSng(toValue),
                fullDistance)

            _valueMotionRunner = MASMotionSystem.CreateTimelineRunner(
                owner:=Me,
                consumerName:="MASSlider.ValueScrub",
                plan:=plan,
                requestFrame:=AddressOf InvalidateVisual,
                applyFrame:=AddressOf ApplyValueMotionFrame,
                completed:=AddressOf CompleteValueMotionFrame)
            _valueMotionRunner.Start()

            InvalidateVisual()
        End Sub

        Private Sub ApplyValueMotionFrame(frame As MASMotionFrame)
            If frame Is Nothing Then Return
            _visualValue = NormalizeValue(CDbl(frame.Value))
            _hasVisualValueOverride = True
            InvalidateVisual()
        End Sub

        Private Sub CompleteValueMotionFrame(frame As MASMotionFrame)
            StopValueMotion(syncToSemanticValue:=True)
            InvalidateVisual()
        End Sub

        Private Sub StopValueMotion(syncToSemanticValue As Boolean)
            If _valueMotionRunner IsNot Nothing Then
                _valueMotionRunner.Dispose()
                _valueMotionRunner = Nothing
            End If

            If syncToSemanticValue Then
                _visualValue = _value
                _hasVisualValueOverride = False
            End If
        End Sub

        Private Function ResolveKeyboardStep() As Double
            Return MASSliderRangePolicy.ResolveKeyboardStep(_step, _minimum, _maximum)
        End Function

        Private Shared Function FormatValue(value As Double) As String
            Return MASSliderRangePolicy.FormatValue(value)
        End Function


        Private Shared Function ResolveRightToLeft() As Boolean
            Return Nexamas.UI.Localization.MASLocalization.IsCurrentRightToLeft()
        End Function

        Private Shared Function ResolveSurfaceColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.SurfaceTheme IsNot Nothing Then Return ctx.SurfaceTheme.SurfaceMid
            Return SKColors.White
        End Function

        Private Shared Function ResolvePrimaryTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.PrimaryText
            Return Nexamas.UI.Values.Color.Text.Primary
        End Function

        Private Shared Function ResolveMutedTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.MutedText
            Return SKColors.Gray
        End Function

        Private Shared Function ResolveAccentColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.BrandTheme IsNot Nothing Then Return ctx.BrandTheme.BrandPrimary
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Info
            Return SKColors.DodgerBlue
        End Function

        Private Sub ResetPointerState()
            _hoverThumb = False
            _pressedThumb = False
            _dragging = False
        End Sub

        Private Sub RaiseValueChangedSafe()
            Try
                RaiseEvent ValueChanged(Me, EventArgs.Empty)
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException1, "MASSlider.ValueChanged")
            End Try
        End Sub

        Private Sub RaiseRangeChangedSafe()
            Try
                RaiseEvent RangeChanged(Me, EventArgs.Empty)
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(masCaughtException1, "MASSlider.RangeChanged")
            End Try
        End Sub

#End Region

#Region "Dispose"

        Protected Overrides Sub Dispose(disposing As Boolean)
            If disposing Then
                StopValueMotion(syncToSemanticValue:=True)
            End If

            MyBase.Dispose(disposing)
        End Sub

#End Region

    End Class

End Namespace
