Source/Set-GridLayout.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
<#
.SYNOPSIS
Sets applications automatically in a grid layout on the screen
 
.DESCRIPTION
 
Sets applications in an automatic grid layout with predefined formats ('Vertical','Horizontal','Mosaic') using the Process object of the target applications
passed as a parameter(-Process) value and also brings the window(s) of the target application(s) to the foreground
 
A custom format can also be used to set the applications in a grid-layout on the display, by passing a custom string as a value to the parameter(-Custom).
 
Run below commands to see some examples
 
    Get-Help Set-GridLayout -Examples
 
.PARAMETER Process
Process(s) objects of the application(s) you want to set in a grid-layout
 
.PARAMETER Vertical
Switch to align application(s) in 'Vertical' grid-layout
 
.PARAMETER Horizontal
Switch to align application(s) in 'Horizontal' grid-layout
 
.PARAMETER Mosaic
Switch to align application(s) in 'Mosaic' grid-layout, that can best fit 'n' number of application(s) in rows
 
.PARAMETER Custom
Accepts a Customizable grid-layout format like '***,**,*,****'
Where '*' represent an application and ',' separates a row in the grid-layout"
So, with custom format = '***,**,*,****' in the grid layout
    Row1 has 3 applications
    Row2 has 2 applications
    Row3 has 1 applications
    Row4 has 4 applications
.PARAMETER IncludeSource
Switch parameter that includes the source process that executes the cmdlet in the th Grid-Layout.
.EXAMPLE
Get-Process notepad | Set-GridLayout
 
Capture all running notepad process objects and set them in 'Mosaic' (Default) grid-layout.
 
.EXAMPLE
$Process = @()
$Process = 1..3 | Foreach {(Start-Process Powershell.exe -WorkingDirectory c:\ -PassThru)}
$Process += 1 | Foreach {(Start-Process notepad.exe -PassThru)}
$Process += 1..5 | Foreach {(Start-Process cmd.exe -WorkingDirectory c:\ -PassThru)}
 
Get the Process objects of target applications,
 
Set-GridLayout -Process $Process
 
then run the below cmdlet to set them in 'Mosaic' (Default) grid-layout.
 
 
.EXAMPLE
Set-GridLayout $Process -layout Vertical
 
Use the 'Layout' parameter set the applications in a 'Vetrical' grid-layout
 
 
.EXAMPLE
Set-GridLayout -Process $Process -Layout Horizontal
 
Use the 'Layout' parameter set the applications in a 'Horizontal' grid-layout
 
 
.EXAMPLE
Set-GridLayout -Process $Process -Custom '**,**,*,****'
 
To set applications is custom grid-layout utilize the 'Custom' parameter and pass the custom layout as comma-separated string of '*' (Astrix)
 
Where '*' represent an application and ',' separates a row in the grid-layout"
So, with custom format = '***,**,*,****' in the grid layout
    Row1 has 3 applications
    Row2 has 2 applications
    Row3 has 1 applications
    Row4 has 4 applications
 
.EXAMPLE
Grid $Process
 
'grid' is an alias of cmdlet Set-GridLayout
 
.EXAMPLE
sgl $Process -Layout Vertical
 
'sgl' is an alias of cmdlet Set-GridLayout
 
.INPUTS
System.Diagnostics.Process
 
.OUTPUTS
None
 
.NOTES
Author : Prateek Singh
TechnologyBlog : http://Geekeefy.wordpress.com
Twitter : http://twitter.com/SinghPrateik
Github : http://github.com/PrateekKumarSingh
LinkedIn : http://in.linkedIn.com/in/PrateekSingh1590
Reddit : http://Reddit.com/user/PrateekSingh1590
Medium : http://Medium.com/@SinghPrateik
 
#>

Function Set-GridLayout {
    [CmdletBinding(
        DefaultParameterSetName = 'default'
    )]
    [Alias("sgl", "grid")]
    Param(
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'Custom',
            ValueFromPipeline=$true,
            Position=0,
            HelpMessage = "Provide a System.Diagnostics.Process[] object"
            )]

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'default',
            ValueFromPipeline=$true,
            Position=0,
            HelpMessage = "Provide a System.Diagnostics.Process[] object"
        )] [System.Diagnostics.Process[]] $Process,
        [Parameter(ParameterSetName = 'default')] [ValidateSet('Vertical', 'Horizontal', 'Cascade', 'Mosaic')] [string] $Layout='Mosaic',
        [Parameter(ParameterSetName = 'Custom')]
        [ValidateScript({
                            If ($_ -match '^[-\w\s\*]+(?:,[-\w\s\*]+)*$'){$True}
                            Else {
                                Throw "`nAccepted custom grid format is something like -custom '***,**,*,****' `nhere '*' represent an application and ',' separates a row in the grid-layout"
                            }
        })] [String] $Custom,
        [Switch] $IncludeSource
    )

    Add-Type -AssemblyName System.Windows.Forms
    $Monitor = [System.Windows.Forms.Screen]::AllScreens.Where( {$_.Primary -eq $true }).Bounds
    $vRes = $monitor.Height -40  # -40 to make the edges appear above the task bar
    $hRes = $monitor.Width

    # Handling the Layout verbosity
    if($Custom){
        Write-Verbose "Setting Processes in Custom layout"
    }else{
        Write-Verbose "Setting Processes in $Layout layout"
    }

    # Handling the pipeline input with -IncludeSource switch
    if($IncludeSource -and $Input){ # when PipelineInput = $true AND $IncludeSource = $true
        $Process = $Input + $(Get-ParentProcess)
    }
    elseif($IncludeSource -and $Process){ # when PipelineInput = $false AND $IncludeSource = $true
        $Process = $Process + $(Get-ParentProcess)
    }
    elseif($Input -and -not $IncludeSource){ # when PipelineInput = $true AND $IncludeSource = false
        $Process = $Input
    }

    # when PipelineInput = $false AND $IncludeSource = false
    $Count = $Process.Count

    if($Layout -eq 'Vertical'){
        $Height = $vRes
        $Width = $hRes/$Count
        $Position = 0

        $Process | ForEach-Object {
            MoveApplication -Process $_ -X $Position -Y 0 -Height $Height -Width $Width
            $Position += $Width
        }
    }
    elseif($Layout -eq 'Horizontal') {
        $Height = $vRes/$Count
        $Width = $hRes
        $Position = 0

        $Process | ForEach-Object {
            MoveApplication -Process $_ -X 0 -Y $Position -Height $Height -Width $Width
            $Position += $Height
        }
    }
    elseif($Layout -eq 'Cascade') {
        $Height = $vRes/1.5
        $Width = $hRes/1.2
        $X = 40
        $y = 40

        $Process | ForEach-Object {
            MoveApplication -Process $_ -X $X -Y $Y -Height $Height -Width $Width
            $X += 25 ;  $Y += 25
        }
    }
    elseif ($Layout -eq 'Mosaic'){
        $PositionX = 0
        $PositionY = 0
        $Rows = 2 #Row more than 2 won't be able to display data properly, hence made it static
        $even = $Count%2 -eq 0

        If($even){
            $Col = 0
            $Columns = $Count/$Rows
            $Height = $vRes/$Rows
            $Width = $hRes/$Columns

            For($i =0 ;$i -lt $Count;$i++)
            {
                $Col++
                If($col -gt $Columns){
                    $PositionX = 0
                    $Col = 0
                    $PositionY = $Height
                }

                MoveApplication -Process $Process[$i] -X $PositionX -Y $PositionY -Height $Height -Width $Width
                $PositionX += $Width
            }
        }
        else{
            $Col = 0
            $Columns = [math]::Floor($Count/$Rows)
            $Height = $vRes/$Rows
            $Width = $hRes/$Columns

            For($i =0 ;$i -lt $Count;$i++)
            {
                $Col++
                If($col -gt $Columns){
                    ++$Columns
                    $Width = $hRes/$Columns
                    $PositionX = 0
                    $Col = 0
                    $PositionY = $Height
                    MoveApplication -Process $Process[$i] -X $PositionX -Y $PositionY -Height $Height -Width $Width
                }
                else {
                    MoveApplication -Process $Process[$i] -X $PositionX -Y $PositionY -Height $Height -Width $Width
                }
                $PositionX += $Width
            }
        }
    }

    if ($Custom) {
        $AppsPlacedInGrid = 0
        $XCoordinate = 0 ; $YCoordinate = 0
        $RowArray = ($Custom -split ",").foreach({$_.ToCharArray().Where({$_ -eq '*'}) -join ''})
        $Ratio = Get-ApplicationRatio -String $Custom

        $NumberOfRows = $RowArray.count
        $NumberOfApps = ( ($RowArray -join '') -replace ",","").length
        $height = $vRes/$NumberOfRows

        if($NumberOfApps -ne $Process.Count){
            throw "Number of apps = $NumberOfApps in custom grid layout is not equal to the Process Id's passed = $($Process.Count)"
        }
        else{
            # Iterate through each row
            For($i=0;$i -lt $NumberOfRows;$i++){
                $NumberOfAppsInCurrentRow = $RowArray[$i].Length
                $RowApplicationRatioArray =  $Ratio[$i] -split ':'
                #$N = ($RowApplicationRatio -split ':' | Measure-Object -Sum).Sum
                $width = $hRes / $(($RowApplicationRatioArray | Measure-Object -Sum).Sum)
                #$width = $hRes / $NumberOfAppsInCurrentRow

                $j = 0 # counter to access application ratio per row

                # Iterate through ProcessID's
                $Process[$AppsPlacedInGrid..$($AppsPlacedInGrid+$NumberOfAppsInCurrentRow-1)] | ForEach-Object {
                    # Set application in a grid with coordinates, height and width
                    $CurrentAppplicationWidth = $Width * $RowApplicationRatioArray[$j] # base width multiplied by the ratio
                    MoveApplication -Process $_ -X $XCoordinate -Y $YCoordinate -Height $Height -Width $CurrentAppplicationWidth
                    $XCoordinate += $CurrentAppplicationWidth # move the XCoordinate of next app to the width of previous app
                    $AppsPlacedInGrid++
                    $j++ # Next application ratio in the Row
                }
                $YCoordinate += $height # Change YCoordinates for every row
                $XCoordinate = 0 # XCoordinate resets after every row
            }
        }
    }
}