PoshCode Logo PowerShell Code Repository

Start-Presentation by Joel Bennett 17 months ago (modification of post by Joel Bennett view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2106"></script>download | new post

My current (WPF 4 compatible) PowerBoots-based Presentation Module. REQUIRES PresentationFrame.xaml and, of course, PowerBoots

This isn’t really ready to be shared, but I always tell people if you wait until after you have time to clean it up, you’ll never share it — so since I’m unlikely to actually finish cleaning this up any time soon — here it is. See the screenshots for an example

  1. if(-not(get-command New-System.Windows.Window -EA 0)){  Import-Module PowerBoots  }
  2. Add-BootsTemplate $PSScriptRoot\PresentationFrame.xaml
  3.  
  4. $name = [System.Windows.Navigation.JournalEntry]::NameProperty
  5. [double]$global:zoomLevel = 1
  6. $SlideCount = 0
  7.  
  8. function Start-Zoom {
  9. PARAM(
  10.    [Parameter(Position=0)]
  11.    $Zoom = 0
  12. ,
  13.    [Parameter(ValueFromPipeline=$true)]
  14.    $Root = $($global:Frame)
  15. ,
  16.    [Parameter()]
  17.    $Window = $presentationTitle
  18. )
  19. $null =  Invoke-BootsWindow $Window {
  20.    Param($Window,$Root)
  21.    if(!$Root.RenderTransform.Children) {
  22.       $Root.RenderTransform = TransformGroup {
  23.          ScaleTransform -ScaleX $zoomLevel -ScaleY $zoomLevel
  24.          TranslateTransform
  25.       }
  26.  
  27.       $BootsWindow.Add_MouseDown( {
  28.          if($zoomLevel -ne 1) {
  29.             trap { Write-Host $( $_ | fl * | out-string ) }
  30.             $global:MouseDownPoint = [System.Windows.Input.Mouse]::GetPosition($BootsWindow)
  31.             $this.CaptureMouse()
  32.          }
  33.       } )
  34.       $BootsWindow.Add_MouseUp( {
  35.          if($zoomLevel -ne 1) {
  36.             trap { Write-Host $( $_ | fl * | out-string ) }
  37.             $this.ReleaseMouseCapture()
  38.          }
  39.       } )
  40.       $BootsWindow.Add_MouseMove( {
  41.          if($zoomLevel -ne 1) {
  42.             trap { Write-Host $( $_ | fl * | out-string ) }
  43.             if($_.LeftButton -eq "Pressed") {
  44.                $newPos = [System.Windows.Input.Mouse]::GetPosition($BootsWindow)
  45.  
  46.                $this.Content.RenderTransform.Children[1].SetValue(
  47.                   [System.Windows.Media.TranslateTransform]::XProperty,
  48.                   $this.Content.RenderTransform.Children[1].Value.OffsetX + ($newPos.X - $MouseDownPoint.X) )
  49.  
  50.                $this.Content.RenderTransform.Children[1].SetValue(
  51.                   [System.Windows.Media.TranslateTransform]::YProperty,
  52.                   $this.Content.RenderTransform.Children[1].Value.OffsetY + ($newPos.Y - $MouseDownPoint.Y) )
  53.  
  54.                $global:MouseDownPoint = $newPos;
  55.             }
  56.          }
  57.       } )
  58.    }
  59. } $Root
  60. }
  61.  
  62. function Set-Zoom {
  63. PARAM(
  64.    [Parameter(Position=0)]
  65.    $Zoom = 0
  66. ,
  67.    [Parameter()]
  68.    $Root = $global:Frame
  69. ,
  70.    [Parameter()]
  71.    $Window = $presentationTitle
  72. )
  73.    if($Zoom -gt 0) {
  74.       $global:zoomLevel *= (1+($Zoom/10))
  75.    } elseif($Zoom -lt 0) {
  76.       $global:zoomLevel /= (1+($Zoom/-10))
  77.    } else {
  78.       $global:zoomLevel = 1.0
  79.    }
  80.    
  81. $null = Invoke-BootsWindow $Window {
  82.    Param($Window,$Root)
  83.    $Root.RenderTransform.Children[0].SetValue(
  84.       [System.Windows.Media.ScaleTransform]::ScaleXProperty, $zoomLevel )
  85.  
  86.    $Root.RenderTransform.Children[0].SetValue(
  87.       [System.Windows.Media.ScaleTransform]::ScaleYProperty, $zoomLevel )
  88.  
  89.    ## Note that we have to account for rounding errors ;)
  90.    if([Math]::Round($zoomLevel, 10) -eq 1.0 ) {
  91.       $Root.NavigationUIVisibility = "Visible"
  92.      
  93.       $Root.RenderTransform.Children[1].SetValue(
  94.          [System.Windows.Media.TranslateTransform]::XProperty, 0.0 )
  95.  
  96.       $Root.RenderTransform.Children[1].SetValue(
  97.          [System.Windows.Media.TranslateTransform]::YProperty, 0.0 )      
  98.    } else {
  99.       $Root.NavigationUIVisibility = "Hidden"
  100.    }
  101. } $Root
  102. }
  103.  
  104. function Show-Url {
  105. [CmdletBinding()]
  106. PARAM(
  107.    [Parameter(Position=0, ValueFromPipeline=$true)]
  108.    [Uri]$Content
  109. ,
  110.    [Parameter()]
  111.    $Window = $presentationTitle
  112. )
  113. Invoke-BootsWindow $Window {
  114.    $global:Frame.Navigate( $Content )
  115. }
  116. }
  117. New-Alias Navigate Show-Url  # backwards compat
  118.  
  119. function Add-Slide {
  120. #.Synopsis
  121. #  Add a slide to the presentation
  122. #.Description
  123. #  Add any .net object as a slide to a presentation, wrapping it in a Page to set the title.
  124. [CmdletBinding(DefaultParameterSetName="Script")]
  125. PARAM(
  126.    [Parameter(Position=0,ValueFromPipelineByPropertyName=$true)]
  127.    [Alias("Name")]
  128.    [String]$Title   = "Slide $SlideCount"
  129. ,  [Parameter(Position=1, ValueFromPipeline=$true, Mandatory=$true)]
  130.    $Content
  131. ,  [Parameter()]
  132.    $Window = $presentationTitle
  133. )
  134. PROCESS {
  135.    $SlideCount++
  136.    Invoke-BootsWindow $Window {
  137.       Param($Frame, $Content, $Title)
  138.       $Frame.Content = Page -Content $Content -Title $Title
  139.    } $global:Frame $Content $Title
  140. }
  141. }
  142.  
  143. function Add-TextSlide {
  144. #.Synopsis
  145. #  Add a text slide to the presentation
  146. #.Description
  147. #  Add a textual slide to the presentation with a header and several points
  148. [CmdletBinding()]
  149. PARAM(
  150.    [Parameter(Position=0)]
  151.    $Title   = "Slide $SlideCount"
  152. ,  [Parameter(Position=1, ValueFromPipeline=$true)]
  153.    [string[]]$Content = @("Several bullet points", "Which are equally important")
  154. ,  [Parameter()]
  155.    $Window = $presentationTitle
  156. )
  157. BEGIN   { [string[]]$global:Points = @() }
  158. PROCESS { [string[]]$global:Points += $Content }
  159. END {
  160.    Add-Slide -Title $Title -Window $Window -Content {
  161.       StackPanel -Margin 10 {
  162.          grid {
  163.             TextBlock $Title  -FontSize 85 -FontFamily Impact -Foreground White -Effect { BlurEffect -Radius 15 } -TextAlign Center
  164.             TextBlock $Title  -FontSize 85 -FontFamily Impact -Foreground $global:TitleBrush -TextAlign Center
  165.          }
  166.          write-host "Points: $Points"
  167.          $Points | % {
  168.             TextBlock $_ -FontSize 64 -FontWeight Bold -Foreground "White" -TextWrapping Wrap -Effect { DropShadowEffect -BlurRadius 15 }
  169.          }
  170.       }
  171.    }.GetNewClosure()
  172. }
  173. }
  174.  
  175. function Add-TitleSlide {
  176. #.Synopsis
  177. #  Add a text slide to the presentation
  178. #.Description
  179. #  Add a textual slide to the presentation with a header and several points
  180. [CmdletBinding()]
  181. PARAM(
  182.    [Parameter(Position=0)]
  183.    $Title
  184. ,   [Parameter()]
  185.    $Window = $presentationTitle
  186. )
  187. BEGIN   { [string[]]$Points = @() }
  188. PROCESS { [string[]]$Points += $Content }
  189. END {
  190.    Add-Slide -Title $Title -Window $Window -Content {
  191.       Grid {
  192.          TextBlock $Title `
  193.             -FontSize 125 -FontFamily Impact -Foreground White `
  194.             -VerticalAlignment Center -TextAlignment Center    `
  195.             -HorizontalAlignment Stretch -TextWrapping Wrap    `
  196.             -Effect { BlurEffect -Radius 20 }
  197.          TextBlock $Title `
  198.             -FontSize 125 -FontFamily Impact -Foreground White `
  199.             -VerticalAlignment Center -TextAlignment Center    `
  200.             -HorizontalAlignment Stretch -TextWrapping Wrap    `
  201.             -Effect { BlurEffect -Radius 20 }
  202.          TextBlock $Title `
  203.             -FontSize 125 -FontFamily Impact -Foreground $global:TitleBrush `
  204.             -VerticalAlignment Center -TextAlignment Center    `
  205.             -HorizontalAlignment Stretch -TextWrapping Wrap    `
  206.             -Effect {DropShadowEffect -Color White -Radius 15}
  207.       }
  208.    }
  209. }
  210. }
  211.  
  212. function Remove-Slide {
  213. #.Synopsis
  214. #  Removes the specified slide from the deck (history)
  215. #.Description
  216. #  Takes an index or name, and removes that slide, except that you CANNOT remove the last slide.
  217. PARAM(
  218.    [Parameter(ParameterSetName="ByIndex", Mandatory=$true, Position=0)]
  219.    [int]$index
  220. ,  [Parameter(ParameterSetName="ByTitle",  Mandatory=$true, Position=0)]
  221.    [Alias("Name")]
  222.    [string]$Title
  223. ,  [Parameter()]
  224.    $Window = $presentationTitle
  225. )
  226.    $null = Invoke-BootsWindow $Window {
  227.       # Figure out where we are now, because we'll need to come back
  228.       $global:currentSlide = @($global:Frame.BackStack.GetEnumerator()).Count
  229.       # Activate the slide they want to delete ...
  230.       [int]$removable = Set-Slide @PsBoundParameters -passthru
  231.    }
  232.    # Separate Invoke's are required for the window to register what's going on?
  233.    $global:removable = $true
  234.    $null = Invoke-BootsWindow $Window {
  235.       if($global:Frame.CanGoForward) {
  236.          $global:Frame.GoForward()
  237.       } else {
  238.          $global:removable = $false
  239.          Write-Host "Sorry, you can't remove the last slide in the deck." -Fore Red
  240.       }
  241.    }
  242.    if($global:removable) {
  243.       # Separate Invoke's are required for the window to register what's going on?
  244.       Invoke-BootsWindow $Window {
  245.          $null = $global:Frame.RemoveBackEntry()
  246.          Set-Slide $currentSlide
  247.       }
  248.    }
  249. }
  250.  
  251. function Show-Slide {
  252. #.Synopsis
  253. #  Set the active slide in a deck
  254. #.Description
  255. #  Sets the active slide by index or name (title)
  256. [CmdletBinding(DefaultParameterSetName="ByIndex")]
  257. PARAM(
  258.    [Parameter(ParameterSetName="ByIndex", Mandatory=$true, Position=0)]
  259.    [int]$index
  260. ,  [Parameter(ParameterSetName="ByTitle",  Mandatory=$true, Position=0)]
  261.    [Alias("Name")]
  262.    [string]$Title
  263. ,  [Parameter()]
  264.    $Window = $presentationTitle
  265. ,  [Parameter()]
  266.    [Switch]$Passthru
  267. )
  268. switch($PSCmdlet.ParameterSetName) {
  269.    "ByIndex" {
  270.       $null = Invoke-BootsWindow $Window {
  271.          # Figure out where we are now...
  272.          [int]$global:current = @($global:Frame.BackStack.GetEnumerator()).Count
  273.          # Then go where we need to
  274.          for(;$current -lt $index -and $global:Frame.CanGoForward ;$global:current++) {
  275.             $global:Frame.GoForward()
  276.          }
  277.          for(;$current -gt $index -and $global:Frame.CanGoBack ;$global:current--) {
  278.             $global:Frame.GoBack()
  279.          }
  280.       }
  281.       if($Passthru) { return $global:current }
  282.    }
  283.    "ByTitle" {
  284.       [int]$global:result = -1
  285.       [int]$global:current = -1
  286.       $null = Invoke-BootsWindow $Window {
  287.          # Figure out where we are now...
  288.          $global:current = @($global:Frame.BackStack.GetEnumerator()).Count
  289.          # Start with backward history ('cause it's more likely)
  290.          [int]$i = 0;
  291.          foreach($page in $global:Frame.BackStack) {
  292.             if($page.Name -eq $Title) {
  293.                $global:result = $current - $i - 1
  294.                for(;$i -gt $0 -and $global:Frame.CanGoBack;$i--) {
  295.                   $global:Frame.GoBack()
  296.                }
  297.                break;
  298.             }
  299.             $i++
  300.          }
  301.          # Failing that, try forward history
  302.          [int]$i = 0;
  303.          foreach($page in $global:Frame.ForwardStack) {
  304.             if($page.Name -eq $Title) {
  305.                $global:result = $current + $i + 1
  306.                for(;$i -gt $0 -and $global:Frame.CanGoForward ;$i--) {
  307.                   $global:Frame.GoForward()
  308.                }
  309.                break;
  310.             }
  311.             $i++
  312.          }
  313.       }
  314.       if($Passthru) {
  315.          if($global:result -ge 0) {
  316.             return $global:result
  317.          } else {
  318.             return $global:current
  319.          }
  320.       }
  321.    }
  322. }
  323. }
  324. New-Alias Set-Slide Show-Slide # backwards compat
  325.  
  326. function Move-NextSlide {
  327. #.Synopsis
  328. #  Navigates to the next slide (if there is another)
  329. PARAM(
  330.    [Parameter()]
  331.    $Window = $presentationTitle
  332. ,
  333.    [Parameter()]
  334.    [Switch]$Passthru
  335. )
  336.    $DidGo = Invoke-BootsWindow $Window {
  337.       Write-Output $global:Frame.CanGoForward
  338.       if($global:Frame.CanGoForward) {
  339.          $global:Frame.GoForward()
  340.       }
  341.    }
  342.    if($Passthru){ $DidGo }
  343. }
  344. New-Alias Next-Slide Move-NextSlide # backwards compat
  345.  
  346. function Move-PreviousSlide {
  347. #.Synopsis
  348. #  Navigates to the previous slide (if there is another)
  349. PARAM(  
  350.    [Parameter()]
  351.    $Window = $presentationTitle
  352. ,
  353.    [Parameter()]
  354.    [Switch]$Passthru
  355. )
  356.    $DidGo = Invoke-BootsWindow $Window {
  357.       Write-Output $global:Frame.CanGoForward
  358.       if($global:Frame.CanGoBack) {
  359.          $global:Frame.GoBack()
  360.       }
  361.    }
  362.    if($Passthru){ $DidGo }
  363. }
  364. New-Alias Prev-Slide Move-PreviousSlide
  365. New-Alias Previous-Slide Move-PreviousSlide # backwards compat
  366.  
  367. function Start-Presentation {
  368. #.Synopsis
  369. #  Start a presentation window
  370. #.Description
  371. #  This is the kick-off function you have to call to create the presentation window
  372. PARAM(
  373.    $PresentationTitle = "PowerShell Presentation"
  374. ,  $BackgroundImagePath = $(Get-ItemProperty "HKCU:\Control Panel\Desktop" | Select -Expand Wallpaper | Get-ChildItem)
  375. )
  376.  
  377.    $BackgroundImagePath = Convert-Path (Resolve-Path $BackgroundImagePath)
  378.    $global:PresentationTitle = $PresentationTitle
  379.    ## Finally, make the slide window
  380.    Boots -Title $PresentationTitle `
  381.          -Height $([System.Windows.SystemParameters]::PrimaryScreenHeight) `
  382.          -Width $([System.Windows.SystemParameters]::PrimaryScreenWidth)   `
  383.    {
  384.       $global:TitleBrush = LinearGradientBrush -Start "0.5,0" -End "0.5,1" {
  385.          GradientStop -Color "#FF084670" -Offset 0
  386.          GradientStop -Color "#FF084670" -Offset 0.6
  387.          GradientStop -Color "#FF000000" -Offset 0.6
  388.       }
  389.       $global:Frame = Frame -Content {
  390.          Page -Title "Welcome" {
  391.             Grid {
  392.                TextBlock $PresentationTitle `
  393.                   -FontSize 125 -FontFamily Impact -Foreground White `
  394.                   -VerticalAlignment Center -TextAlignment Center    `
  395.                   -HorizontalAlignment Stretch -TextWrapping Wrap    `
  396.                   -Effect { BlurEffect -Radius 30 }
  397.                TextBlock $PresentationTitle `
  398.                   -FontSize 125 -FontFamily Impact -Foreground White `
  399.                   -VerticalAlignment Center -TextAlignment Center    `
  400.                   -HorizontalAlignment Stretch -TextWrapping Wrap    `
  401.                   -Effect { BlurEffect -Radius 30 }
  402.            
  403.                TextBlock $PresentationTitle `
  404.                      -FontSize 125 -FontFamily Impact -Foreground $global:TitleBrush `
  405.                      -VerticalAlignment Center -TextAlignment Center  `
  406.                      -HorizontalAlignment Stretch -TextWrapping Wrap  `
  407.             }
  408.          }
  409.       }
  410.       #Start-Zoom -Root $global:Frame
  411.       $global:Frame
  412.    } -Async -On_SourceInitialized {
  413.         if(Test-Path $BackgroundImagePath) {
  414.            $this.Background = ImageBrush -ImageSource $BackgroundImagePath
  415.         }
  416.       $this.WindowState = "Maximized"
  417.    } -On_KeyDown {
  418.       trap { Write-Host $( $_ | fl * | Out-String ) }
  419.       switch -regex ($_.Key) {
  420.          "Escape" {
  421.             Set-Zoom 0; break;
  422.          }
  423.          "OemPlus|Add" {
  424.             Set-Zoom +1; break;
  425.          }
  426.          "OemMinus|Subtract" {
  427.             Set-Zoom -1; break;
  428.          }
  429.          "MediaNextTrack|BrowserForward|Right" {
  430.             Next-Slide; break;
  431.          }
  432.          "MediaPreviousTrack|BrowserBack|Left" {
  433.             Previous-Slide; break;
  434.          }
  435.       }
  436.    } -On_MouseWheel {
  437.       if($_.Delta -gt 0 ) {
  438.          Set-Zoom +1
  439.       } else {
  440.          Set-Zoom -1
  441.       }
  442.      
  443.    }
  444.    
  445.    # -WindowStyle None -AllowsTransparency $true
  446.  
  447. }
  448.  
  449. function Test-Presentation {
  450.    Start-Presentation "PowerShell for Developers"
  451.    
  452.    Add-TextSlide "Overview" "What is PowerShell?", "How can it help me?", "Should I code for it?", "How do I ..."
  453.    Add-TextSlide "What is PowerShell?" "A .Net Console","A new .Net Language","An admin scripting tool","An app automation engine", "All of the above"
  454.    ls ~\Pictures\Comix | Add-Slide
  455.  
  456.    Set-Slide 0
  457.    
  458.    ## The simple, automatic, force-my-hand slide timer.
  459.    ## One slide, every 20 seconds:
  460.    ## go forward and check if we can go forward again
  461.    while( Move-NextSlide -Passthru ) {
  462.       # note that we have to sleep outside the invoke...
  463.       # otherwise the window can't update
  464.       sleep 20
  465.    }
  466.    
  467. }
  468.  
  469. Export-ModuleMember -Function * -Alias *

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me