PowerPoint – Random IT Utensils https://blog.adamfurmanek.pl IT, operating systems, maths, and more. Mon, 08 Jun 2020 00:06:17 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 PowerPoint as a code — Reusing slides in multiple presentations https://blog.adamfurmanek.pl/2020/10/10/powerpoint-as-a-code-reusing-slides-in-multiple-presentations/ https://blog.adamfurmanek.pl/2020/10/10/powerpoint-as-a-code-reusing-slides-in-multiple-presentations/#respond Sat, 10 Oct 2020 08:00:26 +0000 https://blog.adamfurmanek.pl/?p=3537 Continue reading PowerPoint as a code — Reusing slides in multiple presentations]]> Introduction

When you work on slides for public talks it may happen that you would like to have two similar talks sharing some slides. For instance, one of my talks explains internals of async in C# so I have plenty slides with decompiled code, documentation etc. But my other talk, covering cons of async, has similar part as it also needs to explain some machinery before moving forward. However, I’d like to avoid just copying slides here and there as updating them is much harder. So I’d like to be able to extract common parts and reuse them.

I don’t want to use TeX to do so. I made presentations in TeX and I find it very tedious and time consuming, not to mention that ad-hoc adjustments for events (like theme or first slide) are much harder without proper software in place (or even with it, it’s still TeX). PowerPoint is simple and powerful enough for my needs so I wanted to use it. So I implemented couple of VBA functions to do the job.

So I prepared a PowerPoint deck with macro which merges all building blocks together and I can easily modify the macro to add, remove, reorder, or change slides on the go. Simple enough.

Presentation content

All my talks have similar blocks and use the same theme. I use:

  • Section name
  • Some content
  • About me
  • Agenda
  • Presentation title, Q&A, Thanks

So there is not many building blocks to be used. Let’s go.

Beginnings

Press ALT+F11 and add new module to the presentation, save the file as macro-enabled deck. Now, you can run macros easily with ALT+F8.

First function we need is one to remove all slides and sections from the deck:

Private Sub Cleanup()
    While ActivePresentation.slides.Count > 0
        ActivePresentation.slides(1).Delete
    Wend
    
    While ActivePresentation.SectionProperties.Count > 0
        ActivePresentation.SectionProperties.Delete sectionIndex:=1, deleteSlides:=False
    Wend
End Sub

We call this method once at the beginning.

At the end we need to set the footer with slide numbers, date, and a title:

Private Sub SetFooter(footerText As String)
    footerText = footerText & " - Adam Furmanek"
    With ActivePresentation.SlideMaster.HeadersFooters
        .Footer.Visible = True
        .Footer.text = footerText
        
        .DateAndTime.Visible = True
        .DateAndTime.Format = ppDateTimeFigureOut
        .DateAndTime.UseFormat = True
        
        .SlideNumber.Visible = True
        
        .DisplayOnTitleSlide = False
    End With
    
    For Each slide In ActivePresentation.slides
        With slide.HeadersFooters
            .Footer.Visible = True
            .Footer.text = footerText
            
            .DateAndTime.Visible = True
            .DateAndTime.Format = ppDateTimeFigureOut
            .DateAndTime.UseFormat = True
            
            .SlideNumber.Visible = True
        End With
    Next slide
End Sub

And we need to set title in metadata:

Private Sub SetMetadataTitle(title As String)
    Application.ActivePresentation.BuiltInDocumentProperties.Item("title").Value = title
End Sub

Section name

The simplest slide with just a section name and a subtitle:

Private Sub Section(title As String, subtitle As String)
    ActivePresentation.slides.Add Index:=ActivePresentation.slides.Count + 1, Layout:=ppLayoutSectionHeader
    With ActivePresentation.slides(ActivePresentation.slides.Count)
        .Shapes(1).TextFrame.TextRange = title
        .Shapes(2).TextFrame.TextRange = subtitle
    End With
End Sub

We add slide with specific layout and then update labels.

Some content

Here comes the reusability. We prepare separate deck with any slides we like (the actual “content” of the talk) and then copy them over here:

Private Sub Fragment(path As String)
    Dim slideId As Integer
    slideId = ActivePresentation.slides.Count
    ActivePresentation.slides.InsertFromFile (ActivePresentation.path & "\Fragments\" & path & ".pptx"), slideId
    ActivePresentation.SectionProperties.AddBeforeSlide SlideIndex:=slideId + 1, sectionName:=path
End Sub

You can see how I take the current presentation path, go to Fragments directory and the get specific file. Slides are added at the end. Also, section is created before added slides so it is easy to identify where they come from.

About me

This is basically a single slide just like fragment, however, it is probably exactly the same in all talks so I just store it once and reuse:

Private Sub AboutMe()
    Fragment ("AboutMe")
End Sub

Agenda

Now we want to generate a slide with bulleted list. Since agenda will change for each talk (depending on the content), we’d like to generate it automatically:

Private Sub Agenda(points As Variant)
    ActivePresentation.slides.Add Index:=ActivePresentation.slides.Count + 1, Layout:=ppLayoutText
    
    Dim slide As slide
    Set slide = ActivePresentation.slides(ActivePresentation.slides.Count)
    slide.Shapes(1).TextFrame.TextRange = "Agenda"
    
    Dim text As String
    text = ""
    For i = 0 To UBound(points)
        text = text & LTrim(points(i)) & vbCr
    Next
    slide.Shapes(2).TextFrame.TextRange = text
    For i = 0 To UBound(points)
        If InStr(points(i), "   ") = 1 Then
            slide.Shapes(2).TextFrame.TextRange.paragraphs(i + 1).IndentLevel = 2
        End If
    Next
End Sub

I accept a list of labels and indent them respectively. I call this method like this:

Agenda Array( _
        "Exception mechanisms overview", _
        "Implementation details:", _
        "   How to rethrow, catch everything, and what cannot be handled?", _
        "   When are exceptions thrown and how to stop it?", _
        "   How to handle corrupted state?", _
        "Even more implemenation details:", _
        "   SEH and its frame.", _
        "   .NET and double pass.", _
        "   Thread.Abort implementation.", _
        "   AccessViolation internals.", _
        "   VEH and machine code generation to catch StackOverflowException")

You can see that I insert 3 spaces to indent the label. Obviously, you can extend this as you wish.

Presentation title, Q&A, Thanks

These are almost regular section name slides but they have QR code on them which is added like this:

Private Sub InsertQR(qrCodePath As String, left As Integer, top As Integer, width As Integer, height As Integer)
    ActivePresentation.slides(ActivePresentation.slides.Count).Select
    ActivePresentation.slides(ActivePresentation.slides.Count).Shapes.AddPicture( _
        FileName:=ActivePresentation.path & "\Fragments\" & qrCodePath, _
        LinkToFile:=msoFalse, _
        SaveWithDocument:=msoTrue, _
        left:=left, _
        top:=top, _
        width:=width, _
        height:=height _
        ).Select
End Sub

It copies the picture and puts it directly into the slide.

Now it gets super simple. Q&A:

Private Sub QA(qrCodePath As String)
    Section "Q&A", ""
    InsertQR qrCodePath, 500, 30, 400, 400
End Sub

Presentation title:

Private Sub PresentationTitle(title As String, qrCodePath As String)
    Fragment ("PresentationTitle")
    With ActivePresentation.slides(ActivePresentation.slides.Count)
        .Shapes(1).TextFrame.TextRange = title
    End With
    InsertQR qrCodePath, 700, 30, 200, 200
End Sub

Thanks:

Private Sub Thanks(qrCodePath As String)
    Fragment ("Thanks")
    InsertQR qrCodePath, 500, 30, 400, 400
End Sub

Merging things together

All helper methods are private. Now we need to actually define one macro which will compose everything together:

Sub combineExisting()
    Dim slides As Variant
    Dim fileTitle As String
    Dim qrCode As String
    
    Cleanup
    
    ' Settings ========================================
    fileTitle = "Internals of Exceptions"
    qrCode = "Exceptions\InternalsOfExceptionsQR.png"
    
    ' Content ========================================
    
    Fragment "Exceptions\Quote_ExceptionalSituations"
    PresentationTitle "Internals of Exceptions", qrCode
    AboutMe
    Agenda Array( _
        "Exception mechanisms overview", _
        "Implementation details:", _
        "   How to rethrow, catch everything, and what cannot be handled?", _
        "   When are exceptions thrown and how to stop it?", _
        "   How to handle corrupted state?", _
        "Even more implemenation details:", _
        "   SEH and its frame.", _
        "   .NET and double pass.", _
        "   Thread.Abort implementation.", _
        "   AccessViolation internals.", _
        "   VEH and machine code generation to catch StackOverflowException")
        
    Section "Exception mechanisms overview", ""
    Fragment "Exceptions\CppCsharpTryCatchFinallySyntax"
    Fragment "Exceptions\SehVehSyntax"
    Fragment "Exceptions\ExceptionQuestionsOneMightAsk"
    
    Section "Implementation details", ""
    Fragment "Exceptions\Stacktraces"
    Fragment "Exceptions\CatchingEverythingAndUncatchable"
    Fragment "Exceptions\FixingUsing"
    Fragment "Exceptions\FinalizerDuringExit"
    Fragment "Exceptions\OutOfBandExceptions"
    Fragment "Exceptions\ConstrainedExecutedRegion"
    
    Section "Even more implementation details", ""
    Fragment "Exceptions\HowIsExceptionThrown"
    Fragment "Exceptions\ExceptionsInWinDBG"
    Fragment "Exceptions\SehVehInternals"
    Fragment "Exceptions\IlExceptionsMetadata"
    Fragment "Exceptions\TryPerformanceInCsharp"
    Fragment "Exceptions\LockNopBug"
    Fragment "Exceptions\TwoPassExceptionSystem"
    Fragment "Exceptions\ThreadAbortInternals"
    Fragment "Exceptions\AccessViolationAndStackOverflowException"
    
    Section "How to catch SOE?", ""
    Fragment "Exceptions\CatchingSOE"
    
    Fragment "Exceptions\Summary"
    QA qrCode
    Fragment "ReferencesBooks"
    Fragment "Exceptions\ReferencesMyBlog"
    Fragment "Exceptions\ReferencesExternalLinks"
    Thanks qrCode
    
    ' End =============================================
    
    SetFooter fileTitle
    SetMetadataTitle fileTitle
End Sub

I start with defining variables which I’ll use later. I remove all slides. Next, I set settings like common talk name and path to the QR code.
Then goes the table of content. You can see I start with building blocks used together.
Finally, I set the footer on each slide, and update the metadata.

If I now want to add, remove, reorder, or change slides — I simply modify them here in this method. Obviously, actual content needs to be changed in the files stored as fragments. Good thing is it is stored in exactly one place. Recreating slide deck takes around 5 seconds for this table of content so it is good enough for my purposes.

]]>
https://blog.adamfurmanek.pl/2020/10/10/powerpoint-as-a-code-reusing-slides-in-multiple-presentations/feed/ 0