﻿Imports System.ComponentModel
Imports System.Windows.Forms.Design
Imports System.Drawing.Design

'*--->You will have to qualify the name here: [ProjectName].[EditorClassName]<---*'
<Editor("prjShell.BorderStyleEditor", GetType(Drawing.Design.UITypeEditor)), Flags()> _
Public Enum BorderStyle
    None = 0
    Top = 2
    Bottom = 4
    Left = 8
    Right = 16
    All = 2 Or 4 Or 8 Or 16
End Enum

Public Class BorderStyleEditor
    Inherits Drawing.Design.UITypeEditor

    Private _ContentUI As ContentUI

    Public Overrides Function EditValue(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal provider As System.IServiceProvider, ByVal value As Object) As Object
        If (Not provider Is Nothing) Then
            Dim edSvc As Windows.Forms.Design.IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
            If edSvc Is Nothing Then
                Return value
            End If
            If (Me._ContentUI Is Nothing) Then
                Me._ContentUI = New ContentUI
            End If
            Me._ContentUI.Start(edSvc, value)
            edSvc.DropDownControl(Me._ContentUI)
            value = Me._ContentUI.Value
            Me._ContentUI.End()
        End If
        Return MyBase.EditValue(context, provider, value)
    End Function

    Public Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
        Return UITypeEditorEditStyle.DropDown
    End Function

    Private Class ContentUI
        Inherits Control

        Public Sub New()
            Me.InitializeComponent()
            Me.btpPixel.SetPixel(0, 0, SystemColors.ControlDarkDark)
        End Sub

        Public Sub [End]()
            Me.edSvc = Nothing
            Me._Value = Nothing
        End Sub

        Private Sub InitializeComponent()
            Dim ControlSize As New Size(21, 21)
            Dim ParentControlHost As New Control With {.BackColor = SystemColors.Window}
            BorderButtons = New Button() {Me.btnNone, Me.btnAll, Me.btnTop, Me.btnBottom, Me.btnLeft, Me.btnRight}
            MyBase.SetBounds(0, 0, 94, 54)
            '
            'ParentControlHost
            '
            ParentControlHost.Anchor = (AnchorStyles.Right Or (AnchorStyles.Left Or (AnchorStyles.Bottom Or AnchorStyles.Top)))
            ParentControlHost.Location = New Point(2, 2)
            ParentControlHost.Size = New Size(90, 24)
            ParentControlHost.Dock = DockStyle.Fill
            '
            'BorderButtons
            '
            For Each btn As Button In BorderButtons
                With btn
                    .Size = ControlSize
                    .Text = String.Empty
                    .FlatStyle = FlatStyle.Flat
                    .FlatAppearance.BorderColor = SystemColors.Window
                    .BackColor = SystemColors.Window
                    .Tag = False
                    AddHandler .Paint, AddressOf Me.btnPaint
                    AddHandler .MouseEnter, AddressOf OnControlMouseEnter
                    AddHandler .MouseClick, AddressOf OnControlMouseClick
                End With
            Next
            '
            'Add Controls
            '
            MyBase.Controls.Clear()
            MyBase.Controls.Add(ParentControlHost)
            ParentControlHost.Controls.Clear()
            ParentControlHost.Controls.Add(Me.flpMain)
            Me.flpMain.Controls.Clear()
            Me.flpMain.Controls.AddRange(BorderButtons)
        End Sub

        Private Sub btnPaint(ByVal sender As Object, ByVal e As PaintEventArgs)
            Dim btnSender As Button = DirectCast(sender, Button)
            Dim cliRect As Rectangle = btnSender.ClientRectangle
            Me.Cursor = Cursors.Default
            If btnSender.ClientRectangle.Contains(btnSender.PointToClient(Cursor.Position)) Then
                Me.Cursor = Cursors.Hand
                Using sldBrush As New SolidBrush(SystemColors.MenuHighlight)
                    e.Graphics.FillRectangle(sldBrush, btnSender.ClientRectangle)
                End Using
            End If

            Select Case True

                Case btnSender Is Me.btnAll
                    e.Graphics.DrawLine(Pens.Black, 0, 0, cliRect.Width - 1, 0) 'Top
                    e.Graphics.DrawLine(Pens.Black, 0, cliRect.Height - 1, cliRect.Width - 1, cliRect.Height - 1) 'Bottom
                    e.Graphics.DrawLine(Pens.Black, 0, 0, 0, cliRect.Height - 1) 'Left
                    e.Graphics.DrawLine(Pens.Black, cliRect.Width - 1, 0, cliRect.Width - 1, cliRect.Height - 1) 'Right
                Case btnSender Is Me.btnNone
                    Me.DrawDottedLineBottom(e, btnSender)
                    Me.DrawDottedLineLeft(e, btnSender)
                    Me.DrawDottedLineRight(e, btnSender)
                    Me.DrawDottedLineTop(e, btnSender)
                Case btnSender Is Me.btnTop
                    Me.DrawDottedLineLeft(e, btnSender)
                    Me.DrawDottedLineRight(e, btnSender)
                    Me.DrawDottedLineBottom(e, btnSender)
                    e.Graphics.DrawLine(Pens.Black, 0, 0, cliRect.Width - 1, 0) 'Top
                Case btnSender Is Me.btnBottom
                    Me.DrawDottedLineLeft(e, btnSender)
                    Me.DrawDottedLineRight(e, btnSender)
                    Me.DrawDottedLineTop(e, btnSender)
                    e.Graphics.DrawLine(Pens.Black, 0, cliRect.Height - 1, cliRect.Width - 1, cliRect.Height - 1) 'Bottom
                Case btnSender Is Me.btnLeft
                    Me.DrawDottedLineRight(e, btnSender)
                    Me.DrawDottedLineTop(e, btnSender)
                    Me.DrawDottedLineBottom(e, btnSender)
                    e.Graphics.DrawLine(Pens.Black, 0, 0, 0, cliRect.Height - 1) 'Left
                Case btnSender Is Me.btnRight
                    Me.DrawDottedLineLeft(e, btnSender)
                    Me.DrawDottedLineTop(e, btnSender)
                    Me.DrawDottedLineBottom(e, btnSender)
                    e.Graphics.DrawLine(Pens.Black, cliRect.Width - 1, 0, cliRect.Width - 1, cliRect.Height - 1) 'Right
            End Select

            If CBool(btnSender.Tag) Then Me.DrawCheckMark(e, btnSender)

        End Sub

        Protected Overridable Sub DrawCheckMark(ByVal e As PaintEventArgs, ByVal btn As Button)
            Dim cliRect As Rectangle = btn.ClientRectangle
            Using greenPen As New Pen(Color.FromArgb(33, 161, 33))
                e.Graphics.DrawLine(greenPen, 2, 4, 2, 6)
                e.Graphics.DrawLine(greenPen, 3, 5, 3, 7)
                e.Graphics.DrawLine(greenPen, 4, 6, 4, 8)
                e.Graphics.DrawLine(greenPen, 5, 5, 5, 7)
                e.Graphics.DrawLine(greenPen, 6, 4, 6, 6)
                e.Graphics.DrawLine(greenPen, 7, 3, 7, 5)
                e.Graphics.DrawLine(greenPen, 8, 2, 8, 4)
            End Using
        End Sub

        Protected Overridable Sub DrawDottedLineTop(ByRef e As PaintEventArgs, ByVal btn As Button)
            Dim cliRect As Rectangle = btn.ClientRectangle
            For x As Integer = 0 To cliRect.Width Step 2
                e.Graphics.DrawImageUnscaled(btpPixel, x, 0)
            Next
        End Sub

        Protected Overridable Sub DrawDottedLineBottom(ByRef e As PaintEventArgs, ByVal btn As Button)
            Dim cliRect As Rectangle = btn.ClientRectangle
            For x As Integer = 0 To cliRect.Width Step 2
                e.Graphics.DrawImageUnscaled(btpPixel, x, cliRect.Height - 1)
            Next
        End Sub

        Protected Overridable Sub DrawDottedLineRight(ByRef e As PaintEventArgs, ByVal btn As Button)
            Dim cliRect As Rectangle = btn.ClientRectangle
            For y As Integer = 0 To cliRect.Height Step 2
                e.Graphics.DrawImageUnscaled(btpPixel, cliRect.Width - 1, y)
            Next
        End Sub

        Protected Overridable Sub DrawDottedLineLeft(ByRef e As PaintEventArgs, ByVal btn As Button)
            Dim cliRect As Rectangle = btn.ClientRectangle
            For y As Integer = 0 To cliRect.Height Step 2
                e.Graphics.DrawImageUnscaled(btpPixel, 0, y)
            Next
        End Sub

        Protected Overridable Sub OnControlMouseEnter(ByVal sender As Object, ByVal e As System.EventArgs)
            Me.Invalidate()
        End Sub

        Protected Overridable Sub OnControlMouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)
            Dim btnSender As Button = DirectCast(sender, Button)
            btnSender.Tag = Not CBool(btnSender.Tag)

            Select Case True
                Case btnSender Is btnNone AndAlso CBool(btnNone.Tag)
                    For Each btn As Button In Me.BorderButtons
                        If btn IsNot btnSender Then
                            btn.Tag = False
                        End If
                    Next
                Case btnSender Is btnAll AndAlso CBool(btnAll.Tag)
                    For Each btn As Button In Me.BorderButtons
                        If btn IsNot btnSender AndAlso btn IsNot btnNone Then
                            btn.Tag = True
                        ElseIf btn Is btnNone Then
                            btn.Tag = False
                        End If
                    Next
                Case btnSender Is btnRight AndAlso CBool(btnRight.Tag)
                    Me.btnNone.Tag = False
                Case btnSender Is btnLeft AndAlso CBool(btnLeft.Tag)
                    Me.btnNone.Tag = False
                Case btnSender Is btnTop AndAlso CBool(btnTop.Tag)
                    Me.btnNone.Tag = False
                Case btnSender Is btnBottom AndAlso CBool(btnBottom.Tag)
                    Me.btnNone.Tag = False
            End Select
            If (CBool(btnRight.Tag) AndAlso CBool(btnLeft.Tag) AndAlso CBool(btnTop.Tag) AndAlso CBool(btnBottom.Tag)) Then
                Me.btnAll.Tag = True
            Else
                Me.btnAll.Tag = False
            End If
            Me.flpMain.Refresh()
            Me._Value = Me.Style
        End Sub

        Private _Style As BorderStyle
        Private Property Style() As BorderStyle
            Get
                Select Case True
                    Case CBool(Me.btnAll.Tag)
                        Return BorderStyle.All
                    Case CBool(Me.btnNone.Tag)
                        Return BorderStyle.None
                    Case Else
                        Dim btns() As Button = (From b As Button In BorderButtons Select b Where CBool(b.Tag)).ToArray()
                        Dim flag As BorderStyle = Nothing
                        For Each btn As Button In btns
                            If CBool(btn.Tag) Then
                                Select Case True
                                    Case btn Is btnBottom
                                        flag = flag Or BorderStyle.Bottom
                                    Case btn Is btnTop
                                        flag = flag Or BorderStyle.Top
                                    Case btn Is btnLeft
                                        flag = flag Or BorderStyle.Left
                                    Case btn Is btnRight
                                        flag = flag Or BorderStyle.Right
                                End Select
                            End If
                        Next
                        Return flag
                End Select
            End Get
            Set(ByVal value As BorderStyle)
                Select Case value
                    Case BorderStyle.All
                        Me.btnNone.Tag = False
                        Me.btnAll.Tag = True
                        Me.btnBottom.Tag = True
                        Me.btnLeft.Tag = True
                        Me.btnRight.Tag = True
                        Me.btnTop.Tag = True
                        Return
                    Case BorderStyle.None
                        Me.btnNone.Tag = True
                        Me.btnAll.Tag = False
                        Me.btnBottom.Tag = False
                        Me.btnLeft.Tag = False
                        Me.btnRight.Tag = False
                        Me.btnTop.Tag = False
                        Return
                    Case BorderStyle.Top
                        Me.btnTop.Tag = True
                    Case BorderStyle.Right
                        Me.btnRight.Tag = True
                    Case BorderStyle.Left
                        Me.btnLeft.Tag = True
                    Case BorderStyle.Bottom
                        Me.btnBottom.Tag = True
                End Select
                Me.Invalidate()
            End Set
        End Property

        Public Sub Start(ByVal edSvc As IWindowsFormsEditorService, ByVal value As Object)
            Dim BorderStyle As BorderStyle
            Me.edSvc = edSvc
            If DirectCast(value, BorderStyle) = (BorderStyle.All Or BorderStyle.Bottom) Then
                value = BorderStyle.All
            End If
            Me._Value = value
            If value Is Nothing Then BorderStyle = BorderStyle.Top Else BorderStyle = DirectCast(value, BorderStyle)
            Me.Style = BorderStyle
        End Sub

        Protected Overrides ReadOnly Property ShowFocusCues() As Boolean
            Get
                Return True
            End Get
        End Property

        Private _Value As Object
        Public ReadOnly Property Value() As Object
            Get
                Return Me._Value
            End Get
        End Property

        Private btnTop As New Button
        Private btnNone As New Button
        Private btnAll As New Button
        Private btnBottom As New Button
        Private btnLeft As New Button
        Private btnRight As New Button
        Private btpPixel As New Bitmap(1, 1)
        Private BorderButtons() As Button = {}
        Private edSvc As IWindowsFormsEditorService
        Private flpMain As New FlowLayoutPanel With {.Dock = DockStyle.Fill}

    End Class

End Class


