Progress indicator (ppptools.Progress)
Longer-running snippets/actions block the UI thread — without feedback you only see the wait cursor. PPPTools therefore shows a progress indicator that stays animated while your code runs (it runs on its own thread).
There are two levels:
- Automatic — for any run lasting longer than ~0.4 s, a "Running…" window (marquee) with a Cancel button appears. You don't have to do anything.
- With real progress — when your code knows the total (e.g. the number of slides), switch to a percentage bar with
ppptools.Progress(...).
ppptools.Progress(text, total)
var p = ppptools.Progress("Formatting slides…", ppptools.SlideCount);
for (int s = 1; s <= ppptools.SlideCount; s++)
{
p.Report(s, $"Slide {s} of {ppptools.SlideCount}"); // bar + text
FormatShapes(ppptools.GetAllShapes(ppptools.GetSlide(s)));
}
Progress(text, total)— starts the determinate bar (0…total) and returns a handle.Report(value, text)— updates bar and text.Report(text)(text only) also works for indeterminate steps.- The indicator closes automatically at the end of the run (or as soon as you show
ppptools.ShowResult/ResultDialog).
Cancel
The window's "Cancel" behaves as follows:
- With
ppptools.Progress: the nextReport(...)call throws anOperationCanceledException→ your loop stops immediately and cleanly. To react without an exception, checkp.IsCanceled. - Without
Progress(auto indicator only): cancel takes effect at the next checkpoint — for a tight compute loop withoutReportpossibly only at the end. So for reliable cancellation of long runs, useProgress.
Only when needed
Short snippets need nothing — the auto indicator only appears after ~0.4 s. Progress pays off once you iterate over many slides/shapes.
Full example
Search and format text across all slides — with a progress bar, clean cancel handling and a result dialog at the end:
// @param string SearchString "Search term" tooltip="Text to format"
// @param font FormatFont "Format" default="Calibri,18,Bold"
// @button Run
string searchString = Params.GetString("SearchString", "");
var fmt = Params.GetFont("FormatFont");
int replaced = 0;
void FormatShapes(System.Collections.Generic.List<dynamic> shapes)
{
foreach (dynamic sh in shapes)
{
if ((int)sh.HasTextFrame != (int)MsoTriState.msoTrue) continue;
dynamic tr = sh.TextFrame.TextRange;
dynamic found = tr.Find(searchString, 0, MsoTriState.msoFalse, MsoTriState.msoFalse);
while (found != null)
{
found.Font.Name = fmt.Name;
found.Font.Size = fmt.SizeInPoints;
found.Font.Bold = fmt.Bold ? MsoTriState.msoTrue : MsoTriState.msoFalse;
replaced++;
int after = found.Start + found.Length - 1;
found = tr.Find(searchString, after, MsoTriState.msoFalse, MsoTriState.msoFalse);
}
}
}
if (!string.IsNullOrWhiteSpace(searchString))
{
// Progress across all slides
var p = ppptools.Progress("Formatting slides…", ppptools.SlideCount);
try
{
for (int s = 1; s <= ppptools.SlideCount; s++)
{
p.Report(s, $"Slide {s} of {ppptools.SlideCount}"); // Cancel → throws here
FormatShapes(ppptools.GetAllShapes(ppptools.GetSlide(s)));
}
// Result (closes the progress indicator automatically)
ppptools.ShowResult("Done",
$"<b>{replaced}</b> hits formatted across {ppptools.SlideCount} slides.",
"OK", "success");
}
catch (System.OperationCanceledException)
{
// "Cancel" was clicked — report cleanly
ppptools.ShowResult("Cancelled",
$"Stopped early — <b>{replaced}</b> hits formatted so far.",
"OK", "warn");
}
}
Flow: after ~0.4 s the window appears with a percentage bar and "Slide x of y". If the user clicks Cancel, the next p.Report(...) throws an OperationCanceledException → the catch reports how many hits were processed so far. On a normal finish, ShowResult closes the indicator and shows the result.