Command/More/CmxUi.ps1


Import-Module CmxModule -Force -DisableNameChecking

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$VerbosePreference = "continue"
$WarningPreference = "continue" 

$global:TrayIcon = $null
$global:MiniForm = $null

$global:timer = New-Object System.Windows.Forms.Timer
$global:timer.Interval = 2000
$global:timer.Add_Tick({Timer_IntervalElapsed})

$global:finalResult = ""
$global:outputIndex = 0
$global:informationIndex = 0
$global:warningIndex = 0
$global:errorIndex = 0
$global:debugIndex = 0
$global:verboseIndex = 0

function Timer_IntervalElapsed()
{
    Write-Host "Timer event received"
    if($null -ne $global:MiniForm)
    {
        CmxUi_MiniForm_Update
    }


}

function startTimer() 
{ 
    $global:timer.start()
    Write-Host "Start Timer"
}

function stopTimer()
{
    $global:timer.stop()
    Write-Host "Close Function"
    Unregister-Event theTimer
}




function CmxUi_IsProcessRunning
{
    <#
    .SYNOPSIS
    Whether the process, which hosted the systray CmxUi icon, is still running.
    #>


    $scriptName = Split-Path $MyInvocation.ScriptName -Leaf
    $instances = Get-CimInstance Win32_Process -Filter "name = 'powershell.exe'" | Where-Object { $_.CommandLine.Contains($scriptName) }
    if ($instances.Count -gt 0)
    {
        return $true
    }
    return $false
}

function CmxUi_ClosePowershellWindow
{
    $windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
    $asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
    $null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)
}

function CmxUi_GetSettingsPath()
{
    $dataPath = CmxGetDataPath
    $configPath = "$dataPath\MiniForm.json"
    return $configPath
}

function CmxUi_SaveSettings($settingsFile)
{
    if ($global:MiniForm.WindowState -eq [System.Windows.Forms.FormWindowState]::Normal)
    {
        $data = [PsCustomObject]@{
            MiniFormX = $global:MiniForm.Location.X
            MiniFormY = $global:MiniForm.Location.Y
            MiniFormWidth = $global:MiniForm.Width
            MiniFormHeight = $global:MiniForm.Height
        }
        $data | ConvertTo-Json | Out-File $settingsFile        
    }
}

function CmxUi_LoadSettings($settingsFile)
{
    $data = Get-Content $settingsFile | ConvertFrom-Json

    $global:MiniForm.WindowState = [System.Windows.Forms.FormWindowState]::Normal
    $global:MiniForm.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual;
    $global:MiniForm.Location = New-Object System.Drawing.Point($data.MiniFormX, $data.MiniFormY)
    $global:MiniForm.Size = New-Object System.Drawing.Point($data.MiniFormWidth, $data.MiniFormHeight)
}

function CmxUi_LoadSettingsInitial
{
    # load file to form data
    $dataPath = CmxGetDataPath
    $configPath = CmxUi_GetSettingsPath
    if (-not (Test-Path -Path $dataPath -PathType Container))
    {
        New-Item -Path $dataPath -ItemType Directory
    }
    if (-not (Test-Path -Path $configPath -PathType Leaf))
    {
        # Write file
        $global:MiniForm.WindowState = [System.Windows.Forms.FormWindowState]::Normal
        $global:MiniForm.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
        $global:MiniForm.Location = New-Object System.Drawing.Point(0, 0)
        $global:MiniForm.Size = New-Object System.Drawing.Point(400, 600)
        CmxUi_SaveSettings $configPath
    }
    else
    {
        # Read file
        CmxUi_LoadSettings $configPath
    }
}

function CmxUi_OpenMiniForm
{
    if ($null -ne $global:MiniForm)
    {
        Write-Host "MiniForm exists. Try to show it."
        # The form may be minimized, so we restore it.
        $global:MiniForm.WindowState = [System.Windows.Forms.FormWindowState]::Normal
        $global:MiniForm.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
     # $global:MiniForm.BringToFront()
        $global:MiniForm.Focus()
    # $global:MiniForm.Activate()
        return
    }

    if ($null -eq $global:MiniForm)
    {
        Write-Host "MiniForm does not exists. Create it."

        [System.Windows.Forms.Application]::EnableVisualStyles()

        $global:MiniForm = New-Object System.Windows.Forms.Form
        $global:MiniForm.Text = "Mini Form"
        $global:MiniForm.TopMost = $false
        $global:MiniForm.Icon = CmxUi_GetEmergencyIcon
        $global:MiniForm.MinimumSize = New-Object System.Drawing.Size(120, 60)






        CmxUi_LoadSettingsInitial

        $font = New-Object System.Drawing.Font('Microsoft Sans Serif', 10)
        $monospacedFont = New-Object System.Drawing.Font('Consolas', 10)

        $Button1 = New-Object system.Windows.Forms.Button
        $Button1.Text = "StartJob"
        $Button1.Width = 200
        $Button1.Height = 30
      # $Button1.Location = New-Object System.Drawing.Point(10, 10)
        $Button1.Font = $font
        $Button1.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat

        $Label1 = New-Object system.Windows.Forms.Label
        $Label1.Text = "Label1"
        $Label1.Width = 100
        $Label1.Height = 30
     # $Label1.Location = New-Object System.Drawing.Point(220, 10)
        $Label1.Font = $font
        $Label1.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter

        $PictureBox1 = New-Object system.Windows.Forms.PictureBox
        $PictureBox1.Width = 30
        $PictureBox1.Height = 30
    # $PictureBox1.Location = New-Object System.Drawing.Point(330, 10)
        $PictureBox1.imageLocation = CmxUi_GetIconPath("EmergencyStop.ico")
        $PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom

        $ComboBox1 = New-Object system.Windows.Forms.ComboBox
        $ComboBox1.Text = "comboBox"
        $ComboBox1.Width = 100
        $ComboBox1.Height = 30
     # $ComboBox1.Location = New-Object System.Drawing.Point(370, 10)
        @('Item1', 'Item2', 'Item3') | ForEach-Object { [void] $ComboBox1.Items.Add($_) }
        $ComboBox1.Font = $font

        $TextBox1 = New-Object system.Windows.Forms.TextBox
        $TextBox1.Multiline = $true
        # $TextBox1.Width = 400
        # $TextBox1.Height = 400
        # $TextBox1.Location = New-Object System.Drawing.Point(0, 50)
        $TextBox1.Scrollbars = 'Vertical'
        $TextBox1.Font = $monospacedFont
        $TextBox1.ReadOnly = $true
        $TextBox1.Dock = [System.Windows.Forms.DockStyle]::Fill

        $Panel2 = New-Object System.Windows.Forms.FlowLayoutPanel
        $Panel2.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
        # $Panel2.FlowDirection = "TopDown"
        # $Panel2.WrapContents = $false
        $Panel2.AutoSize = $true
        $Panel2.BackColor = 'LightGreen'
        $Panel2.Name = "Panel2"
        $Panel2.BorderStyle = [System.Windows.Forms.FormBorderStyle]::None
        $Panel2.Dock = [System.Windows.Forms.DockStyle]::Left
        $Panel2.Width = 100
        $Panel2.Height = 50
       # $Panel2.Location = New-Object System.Drawing.Point(0, 0)
       $Panel2.Controls.AddRange(@($Button1, $Label1,$PictureBox1, $ComboBox1))

        $Panel3 = New-Object System.Windows.Forms.TableLayoutPanel
        $Panel3.AutoSize = $false
        # $Panel3.FlowDirection = "TopDown"
        # $Panel3.WrapContents = $false
        $Panel3.BackColor = 'Red'
        $Panel3.Name = "Panel3"
        $Panel3.BorderStyle = [System.Windows.Forms.FormBorderStyle]::None
        $Panel3.Dock = [System.Windows.Forms.DockStyle]::Fill
        # $Panel3.Width = 50
        # $Panel3.Height = 100
        #$Panel3.Location = New-Object System.Drawing.Point(50, 0)
        $Panel3.Controls.AddRange(@($TextBox1))

        $Panel1 = New-Object System.Windows.Forms.TableLayoutPanel
        # $Panel1.FlowDirection = "TopDown"
      # $Panel1.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight
      # $Panel1.WrapContents = $false
        $Panel1.AutoSize = $false
        $Panel1.BackColor = 'LightBlue'
        $Panel1.Name = "Panel1"
        $Panel1.BorderStyle = [System.Windows.Forms.FormBorderStyle]::None
        $Panel1.Dock = "Fill"
        #$tableLayoutPanel1.Dock = [System.Windows.Forms.DockStyle]::Fill
        #$Panel1.Controls.Add($HashForAll.PanelLabel,2,0)
        $Panel1.Controls.AddRange(@($Panel2, $Panel3))

       # $global:MiniForm.controls.AddRange(@($Label1, $Button1, $PictureBox1, $ComboBox1, $TextBox1))

        $global:MiniForm.Controls.AddRange(@($Panel1))
        
        $global:MiniForm.Add_FormClosed( { Form_FormClosed })

        $ComboBox1.Add_Click( { ComboBox_OnClick })
        $Button1.Add_Click({ Button_Clicked })

        function Form_FormClosed 
        {
            # save form data to file
            $configPath = CmxUi_GetSettingsPath
            CmxUi_SaveSettings $configPath     
            $global:MiniForm = $null
        }

        function Button_Clicked 
        { 
            #$path = "$global:CmxRootFolder\Command\Environment\GetBuild.ps1"
            $path = "C:\Temp\Test Script.ps1"
            if(Test-Path $path)
            {
                $TextBox1.Text = ""
                $Label1.Text = "(Started)"
                $Button1.Enabled = $false

                $global:outputIndex = 0
                $global:informationIndex = 0
                $global:warningIndex = 0
                $global:errorIndex = 0
                $global:debugIndex = 0
                $global:verboseIndex = 0
                #Start-Job -Name "MyJob" -FilePath $path -ArgumentList 1,2,3
                Start-Job -Name "MyJob" -ScriptBlock { & $args[0] -Blocking $false } -ArgumentList $path
            }
        }

        [void]$global:MiniForm.ShowDialog()
    }


}    


function CmxUi_MiniForm_Update()
{
    $job = Get-Job -Name "MyJob" -ErrorAction Ignore
    if($job.Count -gt 0)
    {
        $jobState = $job.State
        $Label1.Text = $jobState

        # if($jobState -eq 'Blocked')
        # {
        # Start-Job -Name "MyJob" -InputObject "given`r`n"
        # }
        # Merge streams into Output stream not needed
        # $jobResult = Receive-Job $job *>&1
       
        Receive-Job $job
        $childJob = $job.ChildJobs[0]

        $newDataArrived = $false
        while($global:outputIndex -lt $childJob.Output.Count)
        {
            $line = "`r`n OUTPUT " + $childJob.Output[$global:outputIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:outputIndex++
        }
        while($global:informationIndex -lt $childJob.Information.Count)
        {
            $line = "`r`n INFO " + $childJob.Information[$global:informationIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:informationIndex++
        }
        while($global:warningIndex -lt $childJob.Warning.Count)
        {
            $line = "`r`n WARNING " + $childJob.Warning[$global:warningIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:warningIndex++
        }
        while($global:errorIndex -lt $childJob.Error.Count)
        {
            $line = "`r`n ERROR " + $childJob.Error[$global:errorIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:errorIndex++
        }
        while($global:debugIndex -lt $childJob.Debug.Count)
        {
            $line = "`r`n DEBUG " + $childJob.Debug[$global:debugIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:debugIndex++
        }
        while($global:verboseIndex -lt $childJob.Verbose.Count)
        {
            $line = "`r`n VERBOSE " + $childJob.Verbose[$global:verboseIndex]
            $TextBox1.Text += $line
            $newDataArrived = $true
            $global:verboseIndex++
        }

        # Scroll to the bottom of the output
        if($newDataArrived)
        {
            $TextBox1.SelectionStart = $TextBox1.Text.Length;
            $TextBox1.ScrollToCaret()
        }
        if($jobState -eq 'Completed')
        {
            Remove-Job $job
            $Label1.Text = "(Removed)"
            $Button1.Enabled = $true

            Write-Host "finalResult: $global:finalResult"
            $global:finalResult = ""

        }
    }
    else
    {
        $Label1.Text = "(No Job)"
    }
}

function CmxUi_GetIconPath([string]$iconName)
{
    return "$global:CmxRootFolder\Icons\$iconName"
}

function CmxUi_GetEmergencyIcon
{
    $iconPath = CmxUi_GetIconPath("EmergencyStop.ico")
    $icon = New-Object System.Drawing.Icon($iconPath)
    return $icon  
}

function CmxUi_CreateNotifyIcon
{
    $openMiniFormIItem = New-Object System.Windows.Forms.MenuItem
    $openMiniFormIItem.Text = "Open Mini Form"
    
    $exitMenuItem = New-Object System.Windows.Forms.MenuItem
    $exitMenuItem.Text = "Exit"

    $trayContextMenu = New-Object System.Windows.Forms.ContextMenu

    $global:TrayIcon = New-Object System.Windows.Forms.NotifyIcon
    $global:TrayIcon.Text = "CmxUi"
    $global:TrayIcon.Icon = CmxUi_GetEmergencyIcon
    $global:TrayIcon.Visible = $true
    $global:TrayIcon.ContextMenu = $trayContextMenu
    $global:TrayIcon.contextMenu.MenuItems.AddRange($openMiniFormIItem)
    $global:TrayIcon.contextMenu.MenuItems.AddRange($exitMenuItem)

    $global:TrayIcon.Add_MouseDown(
    {
        if ($_.Button -eq [System.Windows.Forms.MouseButtons]::Left)
        {
            CmxUi_OpenMiniForm
        }
        # elseif ($_.Button -eq [System.Windows.Forms.MouseButtons]::Right)
        # {
        # if($null -ne $global:TrayIcon)
        # {
        # $global:TrayIcon.ContextMenu.Show()
        # }
        # }
    })     


    $openMiniFormIItem.Add_Click(
    { 
        CmxUi_OpenMiniForm
    })

    $exitMenuItem.Add_Click(
        {
            $global:TrayIcon.Icon.Dispose()
            $global:TrayIcon.Dispose()
            CmxUi_ExitApplicationContext
            Stop-Process $pid
        })
}

function CmxUi_ExitApplicationContext()
{
    [void][System.Windows.Forms.Application]::Exit()
}

function CmxUi_RunApplicationContext
{
    $appContext = New-Object System.Windows.Forms.ApplicationContext
    [void][System.Windows.Forms.Application]::Run($appContext)
}



# There must be only a single systray icon.
if (CmxUi_IsProcessRunning)
{
    exit 0
}
CmxUi_ClosePowershellWindow
CmxUi_CreateNotifyIcon
startTimer
CmxUi_RunApplicationContext
#[System.GC]::Collect()