# encoding: ascii
# api: powershell
# title: WPK_TunnelGradient
# description: I noticed that WPF has LinearGradient and RadialGradient. Wanted something more… square in size. First tried to use something that allowed me to build brush easy, but it was hard to change it into something portable. So I just used New-Object and now you can use it in WPK, PowerBoots or Show-UI, whichever you prefer. ;) This script is building actual function and shows some demo usage + load required assemblies and makes sure we are in STA (some controls barfed at me when I tried to leave it -MTA). I only hope it’s not done already… ;) Corners are rounded, so that it looks more soft.
# version: 0.5
# type: script
# author: BartekB
# license: CC0
# function: New-TunnelGradientBrush
# x-poshcode-id: 2664
# x-archived: 2011-05-11T01:02:50
# x-published: 2011-05-08T06:14:00
#
#
[CmdletBinding()]
param (
    [string]$InsideColor = 'White',
    [string]$OutsideColor = 'Transparent',
    [int]$BorderThickness = 5
)

Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName WindowsBase

# script requires STA... let us check it.
if ([Threading.Thread]::CurrentThread.GetApartmentState() -eq 'MTA') {
    Write-Warning @'
This script is using controls, that require STA mode. You can:
* Try to run 'PowerShell -STA' and launch the script again
* Run it from PowerShell ISE where STA is default mode.
See you than! ;)
'@
    exit
}

Function New-TunnelGradientBrush {
[CmdletBinding()]
param (
    [Parameter(Mandatory = $true, HelpMessage = 'Color that will fill interior of the brush')]
    [System.Windows.Media.Color]$InsideColor,
    [Parameter(Mandatory = $true, HelpMessage = 'Color that will be used for border of the brush')]
    [System.Windows.Media.Color]$OutsideColor,
    [Parameter(Mandatory = $true, HelpMessage = 'Size of border as part of width, acceptable values: 0 - 0.49')]
    [ValidateRange(0,49)]
    [int]$BorderThickness
)
    Set-StrictMode -Version Latest
    # Prepare few points that will be necessary later in the process...
    
    $Left = New-Object Windows.Point 0, 0.5
    $Right = New-Object Windows.Point 1, 0.5
    $Top = New-Object Windows.Point 0.5, 0
    $Bottom = New-Object Windows.Point 0.5, 1

    $LeftTop = New-Object Windows.Point 0, 0
    $LeftBottom = New-Object Windows.Point 0, 1
    $RightTop = New-Object Windows.Point 1, 0
    $RightBottom = New-Object Windows.Point 1, 1
    
    # Now some values that relate to $BorderTickness selected.
    
    [double]$StartOffset = $BorderThickness / 100
    [double]$EndOffset = - ($BorderThickness / 100) + 1
    $NarrowSize = 100 - 2 * $BorderThickness
    $CornerSize = $BorderThickness
 
    # Build brushes that will be used to create our final brush (VisualBrush)
    
    $GradientStops = New-Object Windows.Media.GradientStopCollection
    @{ 0 = $OutsideColor
        $StartOffset = $InsideColor
        $EndOffset = $InsideColor
        1 = $OutsideColor
    }.GetEnumerator() | Foreach { $GradientStops.Add($(New-Object Windows.Media.GradientStop $_.Value, $_.Name)) }

    $GradientStopsRadial = New-Object Windows.Media.GradientStopCollection
    @{ 1 = $OutsideColor
       0 = $InsideColor
    }.GetEnumerator() | Foreach { $GradientStopsRadial.Add($(New-Object Windows.Media.GradientStop $_.Value, $_.Name)) }
    
    
    $BrushLeftRight = New-Object Windows.Media.LinearGradientBrush -Property @{ 
        StartPoint = $Left 
        EndPoint = $Right 
        GradientStops = $GradientStops
    }

    $BrushTopBottom = New-Object Windows.Media.LinearGradientBrush -Property @{ 
        StartPoint = $Top
        EndPoint = $Bottom 
        GradientStops = $GradientStops
    }
    
    $CommonProperty = @{
        RadiusX = 1 
        RadiusY = 1 
        GradientStops = $GradientStopsRadial
    }

    $BrushLeftTop = New-Object Windows.Media.RadialGradientBrush -Property (@{ 
        Center = $RightBottom 
        GradientOrigin = $RightBottom 
    } + $CommonProperty)

    $BrushLeftBottom = New-Object Windows.Media.RadialGradientBrush -Property (@{ 
        Center = $RightTop 
        GradientOrigin = $RightTop 
    } + $CommonProperty)
        
    $BrushRightTop = New-Object Windows.Media.RadialGradientBrush -Property (@{ 
        Center = $LeftBottom 
        GradientOrigin = $LeftBottom
    } + $CommonProperty)

    $BrushRightBottom = New-Object Windows.Media.RadialGradientBrush -Property (@{ 
        Center = $LeftTop 
        GradientOrigin = $LeftTop
    } + $CommonProperty)
    
    # Create Visual Brush Elements (StackPanels).

    $Horizontal = New-Object Windows.Controls.StackPanel -Property @{
        Background = $BrushLeftRight 
        Width = 100 
        Height = $NarrowSize
    }
    
    $Vertical = New-Object Windows.Controls.StackPanel -Property @{
        Background = $BrushTopBottom 
        Width = $NarrowSize 
        Height = 100
    }
    
    $Corners = @{
        Width = $CornerSize 
        Height = $CornerSize
    }
    
    $TopLeft = New-Object Windows.Controls.StackPanel -Property (@{
        Background = $BrushLeftTop 
        VerticalAlignment = 'Top' 
        HorizontalAlignment = 'Left'
    } + $Corners)

    $BottomLeft = New-Object Windows.Controls.StackPanel -Property (@{
        Background = $BrushLeftBottom 
        VerticalAlignment = 'Bottom' 
        HorizontalAlignment = 'Left'
    } + $Corners)

    $TopRight = New-Object Windows.Controls.StackPanel -Property (@{
        Background = $BrushRightTop 
        VerticalAlignment = 'Top' 
        HorizontalAlignment = 'Right'
    } + $Corners)

    $BottomRight = New-Object Windows.Controls.StackPanel -Property (@{
        Background = $BrushRightBottom 
        VerticalAlignment = 'Bottom' 
        HorizontalAlignment = 'Right'
    } + $Corners)
    
    # Grid that will hold all panels and will be Visual for VisualBrush

    $Grid = New-Object Windows.Controls.Grid
    foreach ($Control in $Vertical, $Horizontal, $BottomLeft, $BottomRight, $TopLeft, $TopRight) {
        $Grid.Children.Add($Control) | Out-Null
    }

    # Send visualBrush to pipe... at last! :)
    New-Object System.Windows.Media.VisualBrush $Grid    
}

# Sample...
try {
    $Brush = New-TunnelGradientBrush -InsideColor $InsideColor -OutsideColor $OutsideColor -BorderThickness $BorderThickness
} catch {
    Write-Host "Try some valid values. -Verbose for more."
    Write-Verbose $_
    exit
}

$Window = New-Object Windows.Window -Property @{
    BackGround = $Brush
    Width = 200
    Height = 200
    WindowStyle = 'None'
    AllowsTransparency = $True
}

$Window.Add_MouseLeftButtonDown({ $this.DragMove() })
$Window.Add_MouseRightButtonDown({ $this.Close() })
$Window.ShowDialog() | Out-Null
