' Copyright (C) 2025  P4pillon.org
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU Affero General Public License as
' published by the Free Software Foundation, either version 3 of the
' License, or (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU Affero General Public License for more details.
'
' You should have received a copy of the GNU Affero General Public License
' along with this program.  If not, see <https://www.gnu.org/licenses/>.
#Region "Imports"
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
'Imports System.Runtime.InteropServices

#End Region

<System.ComponentModel.DefaultProperty("ButtonStyle"), System.ComponentModel.ToolboxItem(True)> _
Public Class BtonStyle
    Inherits System.Windows.Forms.Button

    Private Declare Function SetCursorPos Lib "user32" ( _
                 ByVal x As Int32, _
                 ByVal y As Int32) As Int32

    '  Private Declare Function CreateRoundRectRgn Lib "gdi32.dll" _
    '   (ByVal X1 As Int32, ByVal Y1 As Int32, ByVal X2 As Int32, ByVal Y2 As Int32, ByVal X3 As Int32, ByVal Y3 As Int32) As IntPtr
    '  Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As IntPtr) As Int32

    '  Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle&, _
    'ByVal nWidth&, ByVal crColor&) As Long


    'Private Declare Function SetWindowRgn Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal hRgn As IntPtr, ByVal bRedraw As Boolean) As Int32


    Public Sub New()
        MyBase.New()
        SetStyle(Windows.Forms.ControlStyles.ResizeRedraw, True)
        SetStyle(Windows.Forms.ControlStyles.OptimizedDoubleBuffer, True)
        MyBase.FlatAppearance.BorderColor = SystemColors.Control
        MyBase.FlatStyle = Windows.Forms.FlatStyle.Flat
        MyBase.FlatAppearance.MouseOverBackColor = Color.Transparent
        MyBase.FlatAppearance.MouseDownBackColor = Color.Transparent
        MyBase.FlatAppearance.BorderSize = 0


    End Sub


    ' Déclaration pour propriété
    Private _StyleBouton As Integer
    Private _Focus As Boolean
    Private _3d As Boolean
    Private _StyleFond As StylFnd
    Private _styledégradé As StylColor
    Private _choixFacteur As ChFacteur
    Private XBlend As Blend = New Blend
    Private _brush As Brush
    Private _CurseurSouris As Boolean
    Private Place As Boolean
    'Texte
    Private _StylTexte As StylTexte

    ' La souris
    Private CurseurSouris As _MouseEs = _MouseEs.Leave
    Private CouleurDebut As Color
    Private CouleurFin As Color
    Private BcolorEnd As Drawing.Color
    ' Bouton image arrondie
    Private ImageTransi As Image
    Private _ImgDown As Image
    Private _ImgEnter As Image
    Private _ImgOn As Image

#Region "Enum"
    Public Enum StylBton As Integer
        None
        RectangleArrondie
        Rond
        Image
    End Enum

    Public Enum StylFnd
        Unis
        Dégradé
    End Enum

    Public Enum StylColor
        DiagonalHB
        DiagonalBH
        Horizontal
        Vertical
    End Enum

    Public Enum ChFacteur
        Facteur0
        Facteur1
        Facteur2
        Facteur3
        Facteur4
    End Enum

    Public Enum StylTexte
        Normal
        Relief
        Ombre
        Gravé
    End Enum


    Private Enum _MouseEs
        Enter
        Leave
        Down
        UP
    End Enum
#End Region


#Region "Les propriétées"
    <Description("Style du texte"), Category("BoutonMF"), DefaultValue(GetType(StylBton), "False")> _
Public Property Bs_StylText() As StylTexte
        Get
            Return _StylTexte
        End Get
        Set(ByVal value As StylTexte)
            _StylTexte = value
        End Set
    End Property
    <Description("Pointeur de la souris sur le contrôl qui reçoit le focus"), Category("BoutonMF"), DefaultValue(GetType(StylBton), "False")> _
  Public Property Bs_CurseurMouse() As Boolean
        Get
            Return _CurseurSouris
        End Get
        Set(ByVal value As Boolean)
            _CurseurSouris = value
        End Set
    End Property
    <Description("Image over"), Category("BoutonMF")> _
    Public Property Bs_ImageOver() As Image
        Get
            Return _ImgEnter
        End Get
        Set(ByVal value As Image)
            _ImgEnter = value
        End Set
    End Property
    <Description("Image down"), Category("BoutonMF")> _
    Public Property Bs_ImageDown() As Image
        Get
            Return _ImgDown
        End Get
        Set(ByVal value As Image)
            _ImgDown = value
        End Set
    End Property

    <Description("Image On"), Category("BoutonMF")> _
        Public Property Bs_ImageOn() As Image
        Get
            Return _ImgOn
        End Get
        Set(ByVal value As Image)
            _ImgOn = value
        End Set
    End Property
    <Description("Choisir le style du Bouton"), Category("BoutonMF"), DefaultValue(GetType(StylBton), "None")> _
    Public Property Bs_StyleBouton() As StylBton
        Get
            Return _StyleBouton

        End Get
        Set(ByVal value As StylBton)
            _StyleBouton = value

        End Set
    End Property

    <Description("Effet 3D  "), Category("BoutonMF"), DefaultValue(GetType(StylBton), "False")> _
    Public Property Bs_Effet_3D() As Boolean
        Get
            Return _3d
        End Get
        Set(ByVal value As Boolean)
            _3d = value
            Dessine(MyBase.CreateGraphics)
        End Set
    End Property

    <Description("Style du fond  "), Category("BoutonMF"), DefaultValue(GetType(StylBton), "Unis")> _
    Public Property Bs_StyleCouleurFond() As StylFnd
        Get
            Return _StyleFond
        End Get
        Set(ByVal value As StylFnd)
            _StyleFond = value
        End Set
    End Property

    <Description("Style dégradé  "), Category("BoutonMF"), DefaultValue(GetType(StylBton), "Horizontal")> _
    Public Property Bs_StyleDégradé() As StylColor
        Get
            Return _styledégradé
        End Get
        Set(ByVal value As StylColor)
            _styledégradé = value
        End Set
    End Property

    <Description("Facteur de mélange   "), Category("BoutonMF"), DefaultValue(GetType(StylBton), "Facteur0")> _
    Public Property Bs_ChoixFacteur() As ChFacteur
        Get
            Return _choixFacteur
        End Get
        Set(ByVal value As ChFacteur)
            _choixFacteur = value
        End Set
    End Property

    <Description("Couleur fin dégradé "), Category("BoutonMF")> _
    Public Property Bs_BackcolorEnd() As Color
        Get
            Return BcolorEnd
        End Get
        Set(ByVal value As Color)
            BcolorEnd = value
        End Set
    End Property


#End Region

#Region "Principale"
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Dessine(e.Graphics)

    End Sub
    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
        _Focus = True
        MyBase.OnGotFocus(e)
    End Sub
    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
        _Focus = False : place = False
        MyBase.OnLostFocus(e)
    End Sub
    Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
        _Focus = Nothing
        CurseurSouris = _MouseEs.Enter
        MyBase.OnMouseEnter(e)
    End Sub
    Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
        _Focus = Nothing
        CurseurSouris = _MouseEs.Leave
        MyBase.OnMouseLeave(e)
    End Sub
    Protected Overrides Sub OnMouseDown(ByVal mevent As System.Windows.Forms.MouseEventArgs)
        _Focus = Nothing
        CurseurSouris = _MouseEs.Down
        MyBase.OnMouseDown(mevent)
    End Sub
    Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
        _Focus = Nothing
        CurseurSouris = _MouseEs.UP
        MyBase.OnMouseUp(mevent)
    End Sub
    Private Sub Dessine(ByVal e As Graphics)
        'Dim RegionRect As Rectangle = Me.ClientRectangle
        Dim RegionRect = New Rectangle(0, 0, Me.Width, Me.Height)
        Using ButtonPath As New System.Drawing.Drawing2D.GraphicsPath

            Select Case _StyleBouton
                Case StylBton.RectangleArrondie
                    FormeRectangleArrondie(e, RegionRect, ButtonPath)

                Case StylBton.Rond
                    FormeArrondie(e, RegionRect, ButtonPath)

                Case StylBton.Image
                    Imageshow(e, RegionRect, ButtonPath)


            End Select
        End Using
    End Sub
#End Region

#Region "Change la forme du Bouton"
    Private Sub Imageshow(ByVal e As Graphics, ByVal r As Rectangle, ByVal BPath As GraphicsPath)

        e.SmoothingMode = SmoothingMode.HighQuality

        Dim penx As New Pen(Color.Transparent, 2)
        Select Case CurseurSouris
            Case _MouseEs.Leave
                ImageTransi = _ImgOn
            Case _MouseEs.Enter
                ImageTransi = _ImgEnter
            Case _MouseEs.Down
                ImageTransi = _ImgDown
            Case _MouseEs.UP
                ImageTransi = _ImgOn

        End Select

        If MyBase.Focused = True And Place = False Then
            ' Place le pointeur de la souris sur le control
            If _CurseurSouris = True Then
                Dim Position As Point = Me.PointToClient(Me.Location)
                SetCursorPos((Position.X * -1) + MyBase.Left + MyBase.Width / 2, (Position.Y * -1) + MyBase.Top + MyBase.Height / 2)
                Place = True
            End If
        End If

        BPath.AddEllipse(0, 0, MyBase.Width, MyBase.Height)

        MyBase.Region = New Region(BPath)

        Try
            e.DrawImage(Me.ImageTransi, r)
            Me.Size = New Size(Me.Bs_ImageOn.Width, Me.Bs_ImageOn.Height)
        Catch ex As Exception
        End Try

    End Sub

    ' Forme Rectangle arrondie
    Private Sub FormeRectangleArrondie(ByVal e As Graphics, ByVal r As Rectangle, ByVal BPath As GraphicsPath)
        Dim pen_x As Pen = Nothing
        Dim pen_y As Pen = Nothing
        Dim pen_z As Pen = Nothing
        '

        Dim Adjust As Single = IIf(r.Height Mod 2 = 0, 0, 1)
        e.SmoothingMode = SmoothingMode.HighQuality
        '

        ' Choix du fond
        ChoixFOnd(e, r)


        ' Focus
        Try
            e.DrawImageUnscaled(Me.Image, Pos_Image)
        Catch ex As Exception

        End Try


        If _Focus = True Then
            pen_x = New Pen(Color.Yellow, 2)
            pen_x.DashStyle = DashStyle.Custom
            ' Place le pointeur de la souris sur le control
            If _CurseurSouris = True Then
                Dim Position As Point = Me.PointToClient(Me.Location)
                SetCursorPos((Position.X * -1) + MyBase.Left + MyBase.Width / 2, (Position.Y * -1) + MyBase.Top + MyBase.Height / 2)
            End If
        Else
            pen_x = New Pen(Me.FlatAppearance.BorderColor, 2)
            pen_x.DashStyle = DashStyle.Solid
        End If

        'r.Inflate(-2, -2)
        With r
            'AJoute Première ligne
            BPath.AddLine(.Left + CType((.Height / 2), Single), .Top, .Right - CType((.Height / 2), Single), r.Top)
            ''Add Right Semi Circle
            BPath.AddArc(.Right - .Height, .Top, .Height, .Height, 270, 180)
            ''Add Bottom Line
            BPath.AddLine(.Right - CType((.Height / 2), Single) - Adjust, r.Bottom, .Left + CType((.Height / 2), Single) + Adjust, r.Bottom)
            ''Add Left Semi Circle
            BPath.AddArc(.Left, .Top, .Height, .Height, 90, 180)
        End With

        MyBase.Region = New Region(BPath)

        r.Inflate(+5, +5)
        e.DrawPath(pen_x, BPath)
        '  r.Inflate(+15, +15)
        'Effet 3 dimension
        If _3d = True Then
            pen_y = New Pen(Color.White, 1)
            pen_y.DashStyle = DashStyle.Solid
            pen_z = New Pen(Color.Black, 1)
            pen_z.DashStyle = DashStyle.Solid
        Else
            pen_y = New Pen(Me.BackColor, 1)
            pen_y.DashStyle = DashStyle.Solid
            pen_z = New Pen(Me.BackColor, 1)
            pen_z.DashStyle = DashStyle.Solid
        End If

        r.Inflate(-8, -8)
        e.DrawLine(pen_y, r.Left + CType((r.Height / 2), Single), r.Top, r.Right - CType((r.Height / 2), Single), r.Top)
        e.DrawArc(pen_y, r.Right - r.Height, r.Top, r.Height, r.Height, 270, 180)

        e.DrawLine(pen_z, r.Right - CType((r.Height / 2), Single) - Adjust, r.Bottom, r.Left + CType((r.Height / 2), Single) + Adjust, r.Bottom)
        e.DrawArc(pen_z, r.Left, r.Top, r.Height, r.Height, 90, 180)
        ' fin



        pen_z.Dispose()
        pen_x.Dispose()
        pen_y.Dispose()


    End Sub
    ' Bouton Style rond
    Private Sub FormeArrondie(ByVal e As Graphics, ByVal r As Rectangle, ByVal BPath As GraphicsPath)
        e.SmoothingMode = SmoothingMode.HighQuality
        r.Inflate(-20, -20)
        BPath.AddEllipse(19, 19, Me.Width - 38, Me.Height - 38)



        ' Choix du fond
        ChoixFOnd(e, r)



        MyBase.Region = New Region(BPath)

        Dim pen_x As Pen = Nothing
        Dim blackPen As Pen = Nothing
        Dim blackPenx As Pen = Nothing

        Dim pen_y As New Pen(Me.FlatAppearance.BorderColor, Me.FlatAppearance.BorderSize)
        pen_y.DashStyle = DashStyle.Solid
        e.DrawEllipse(pen_y, r)


        If _Focus = True Then
            pen_x = New Pen(Me.FlatAppearance.BorderColor, 1.0F)
            pen_x.DashStyle = DashStyle.Solid
            ' Place le pointeur de la souris sur le control
            If _CurseurSouris = True Then
                Dim Position As Point = Me.PointToClient(Me.Location)
                SetCursorPos((Position.X * -1) + MyBase.Left + MyBase.Width / 2, (Position.Y * -1) + MyBase.Top + MyBase.Height / 2)
            End If

        Else
            pen_x = New Pen(Me.BackColor, 2)
            pen_x.DashStyle = DashStyle.Solid
        End If

        r.Inflate(-3, -3)
        e.DrawEllipse(pen_x, r)

        'Effet 3 dimension
        If _3d = True Then
            blackPen = New Pen(Color.Black, 1)
            blackPenx = New Pen(Color.White, 1)
        Else
            blackPen = New Pen(Me.BackColor, 1)
            blackPenx = New Pen(Me.BackColor, 1)
        End If

        'effet(3D)
        Try
            r.Inflate(1, 1)
            e.DrawArc(blackPen, r, 10, 190)
            e.DrawArc(blackPenx, r, 190, 180)
        Catch ex As Exception

        End Try


        pen_x.Dispose()
        pen_y.Dispose()
        blackPenx.Dispose()
        blackPen.Dispose()
    End Sub

#End Region

#Region "Couleur dégradé"
    Private Sub ChoixFOnd(ByVal e As Graphics, ByVal Rec As Rectangle)

        Select Case _StyleFond
            Case StylFnd.Unis
                Select Case CurseurSouris
                    Case _MouseEs.Leave
                        _brush = New SolidBrush(Me.BackColor)
                    Case _MouseEs.Enter
                        _brush = New SolidBrush(Me.FlatAppearance.MouseOverBackColor)
                    Case _MouseEs.Down
                        _brush = New SolidBrush(Me.FlatAppearance.MouseDownBackColor)
                    Case _MouseEs.UP
                        _brush = New SolidBrush(Me.FlatAppearance.MouseOverBackColor)
                End Select


                e.FillRectangle(_brush, Rec)

            Case StylFnd.Dégradé
                ' Quels chois de dégadé

                Select Case CurseurSouris
                    Case _MouseEs.Leave
                        CouleurDebut = Me.BackColor
                        CouleurFin = BcolorEnd
                    Case _MouseEs.Enter
                        CouleurDebut = Color.Yellow
                        CouleurFin = BcolorEnd
                    Case _MouseEs.Down
                        CouleurDebut = Color.Red
                        CouleurFin = Me.FlatAppearance.MouseDownBackColor
                    Case _MouseEs.UP
                        CouleurDebut = Color.Yellow
                        CouleurFin = BcolorEnd
                End Select

                X_MélangeCouleur()

                Select Case _styledégradé

                    Case StylColor.DiagonalBH

                        Using myLinearGradientBrush As New LinearGradientBrush(Rec, CouleurDebut, CouleurFin, LinearGradientMode.BackwardDiagonal)
                            myLinearGradientBrush.Blend = XBlend
                            e.FillRectangle(myLinearGradientBrush, Rec)
                        End Using

                    Case StylColor.DiagonalHB
                        Using myLinearGradientBrush As New LinearGradientBrush(Rec, CouleurDebut, CouleurFin, LinearGradientMode.ForwardDiagonal)
                            myLinearGradientBrush.Blend = XBlend
                            e.FillRectangle(myLinearGradientBrush, Rec)
                        End Using

                    Case StylColor.Horizontal
                        Using myLinearGradientBrush As New LinearGradientBrush(Rec, CouleurDebut, CouleurFin, LinearGradientMode.Horizontal)
                            myLinearGradientBrush.Blend = XBlend
                            e.FillRectangle(myLinearGradientBrush, Rec)
                        End Using

                    Case StylColor.Vertical
                        Using myLinearGradientBrush As New LinearGradientBrush(Rec, CouleurDebut, CouleurFin, LinearGradientMode.Vertical)
                            myLinearGradientBrush.Blend = XBlend
                            e.FillRectangle(myLinearGradientBrush, Rec)
                        End Using
                End Select


        End Select
        ' Réinscrit le texte
        Select Case _StylTexte
            Case StylTexte.Normal
                TexteNormal(e, Rec)

            Case Else
                TexteForme(e)
        End Select



    End Sub

    Private Sub X_MélangeCouleur()
        Select Case _choixFacteur

            Case ChFacteur.Facteur0
                XBlend.Factors = New Single() {0.0F, 0.32F, 1.0F, 0.7F, 1.0F, 0.7F, 0.5F, 0.2F, 0.0F}
                XBlend.Positions = New Single() {0.0F, 0.1F, 0.3F, 0.4F, 0.5F, 0.6F, 0.7F, 0.8F, 1.0F}

            Case ChFacteur.Facteur1
                XBlend.Factors = New Single() {0.0F, 0.32F, 1.0F}
                XBlend.Positions = New Single() {0.0F, 0.44F, 1.0F}


            Case ChFacteur.Facteur2
                XBlend.Factors = New Single() {0.0F, 0.2F, 0.5F, 0.7F, 1.0F, 0.7F, 0.5F, 0.2F, 0.0F}
                XBlend.Positions = New Single() {0.0F, 0.1F, 0.3F, 0.4F, 0.5F, 0.6F, 0.7F, 0.8F, 1.0F}

            Case ChFacteur.Facteur3
                XBlend.Factors = New Single() {0.0F, 0.72F, 0.0F}
                XBlend.Positions = New Single() {0.0F, 0.1F, 1.0F}

            Case ChFacteur.Facteur4
                XBlend.Factors = New Single() {0.0F, 0.1F, 2.0F, 0.1F, 0.0F}
                XBlend.Positions = New Single() {0.0F, 0.1F, 3.0F, 0.0F, 1.0F}

        End Select

    End Sub
#End Region


#Region "Mode Texte"
    Private Sub TexteNormal(ByVal e As Graphics, ByVal Rect As Rectangle)
        Dim _Brush As SolidBrush
        _Brush = New SolidBrush(Me.ForeColor)
        e.DrawString(Me.Text, Me.Font, _Brush, Rect, PositionText)
    End Sub

    Private Sub TexteForme(ByVal e As Graphics)
        Dim _Size As SizeF = e.MeasureString(Me.Text, Me.Font)
        Dim x As Single = ((Me.Width - _Size.Width) / 2) ' + _TextLoc.X
        Dim y As Single = ((Me.Height - _Size.Height) / 2) ' + _TextLoc.Y
        Dim ex As Single = x + 1
        Dim ey As Single = y + 1
        Dim _Brush As SolidBrush
        Dim xColor As Color = Me.ForeColor
        Dim ycolor As Color = Color.Black
        Select Case _StylTexte
            Case StylTexte.Ombre
                ex += 1 : ey += 1
            Case StylTexte.Gravé
                ex -= 2 : ey -= 2
                xColor = Me.BackColor
                ycolor = Color.White
        End Select

        _Brush = New SolidBrush(ycolor)
        e.DrawString(Me.Text, Me.Font, _Brush, ex, ey)

        _Brush = New SolidBrush(xColor)
        e.DrawString(Me.Text, Me.Font, _Brush, x, y)
    End Sub


    Private Function PositionText() As StringFormat
        Dim Format As New StringFormat

        Select Case Me.TextAlign
            ' Milieu
            Case ContentAlignment.MiddleCenter
                Format.Alignment = StringAlignment.Center
                Format.LineAlignment = StringAlignment.Center
            Case ContentAlignment.MiddleLeft
                Format.Alignment = StringAlignment.Near
                Format.LineAlignment = StringAlignment.Center
            Case ContentAlignment.MiddleRight
                Format.Alignment = StringAlignment.Far
                Format.LineAlignment = StringAlignment.Center
                ' Bas
            Case ContentAlignment.BottomCenter
                Format.Alignment = StringAlignment.Center
                Format.LineAlignment = StringAlignment.Far
            Case ContentAlignment.BottomLeft
                Format.Alignment = StringAlignment.Near
                Format.LineAlignment = StringAlignment.Far
            Case ContentAlignment.BottomRight
                Format.Alignment = StringAlignment.Far
                Format.LineAlignment = StringAlignment.Far
                'Haut
            Case ContentAlignment.TopCenter
                Format.Alignment = StringAlignment.Center
                Format.LineAlignment = StringAlignment.Near
            Case ContentAlignment.TopLeft
                Format.Alignment = StringAlignment.Near
                Format.LineAlignment = StringAlignment.Near
            Case ContentAlignment.TopRight
                Format.Alignment = StringAlignment.Far
                Format.LineAlignment = StringAlignment.Near
        End Select

        Return Format
    End Function
#End Region

#Region "Images"
    Private Function Pos_Image() As Point
        Select Case Me.ImageAlign
            Case ContentAlignment.MiddleLeft
                Pos_Image = New Point(ContentAlignment.MiddleLeft, 0)
            Case ContentAlignment.MiddleCenter
                Pos_Image = New Point(ContentAlignment.BottomCenter)
        End Select
        Return Pos_Image
    End Function
#End Region
End Class


