Progress bar

MProgressBar is the single global progress widget anchored to the right of the menu bar. It exists purely to tell the user that background work is happening – it does not schedule, run, or track tasks. It just shows a bar that fills up as pieces of work report that they have finished. Any module can report at any moment that work needs to be done, registering the work to the progress bar. Using the scheduler (Scheduling in Met.3D) is one option, task submitted to the scheduler are automatically registered to the progress bar. However, scheduling is not a requirement. Session switching, exporting variables to Python, scanning files or compiling shaders all use it without an MTask.

The task-handle contract

You register a unit of work and receive a QSharedPointer<MProgressBarTaskHandle>. Registering a task raises the bar’s maximum by one; the task counts for the progress bar as complete, when the last reference to its handle is destroyed (RAII scheme). The shared pointer carries a custom deleter that notifies the bar. In practice:

  • hold the handle for exactly as long as the work runs, then let it go (scope exit or handle.clear());

  • because it is a QSharedPointer, every copy must be gone before the unit completes. Try to keep a single owner for this handle.

Getting handles

Always through MProgressBar::getInstance():

  • addTask(displayName) – one handle for a single standalone operation.

  • addTasks(n, displayName) – a list of n handles for a batch; drop them one at a time as each unit finishes.

  • addTask(MTask*) – convenience for a scheduled task: it attaches a handle to the MTask (using the task’s processing label as the display name). You do not manage this handle; it is released automatically when the task finishes. The scheduler already does this for pipeline tasks, so ordinary data-source computations show progress without any extra code.

Threading

Handles may be created and released from any thread. The internal counters are mutex-protected and the actual widget repaint is delegated to the UI thread automatically, so you never touch the widget yourself and don’t have to think about which thread you are on.

Examples

A standalone operation – hold one handle for the duration:

{
  auto handle = MProgressBar::getInstance()->addTask("Exporting variables...");
  exportVariables();
} // handle drops at scope exit -> the bar advances

Scanning a collection of files – a batch, one handle released per file:

auto handles = MProgressBar::getInstance()->addTasks(files.size(),
                                                     "Scanning files...");
for (int i = 0; i < files.size(); ++i)
{
    scanFile(files[i]);
    handles[i].clear();   // this unit is done
}

Warning

A handle that is never released keeps its unit “in progress” forever, so the progress bar never completes. Storing a handle in a long-lived member and forgetting to clear it has the same effect as a leak. Try to keep handles only on the stack instead of moving them to the heap, so they will run out of scope automatically.

Conversely, dropping a handle before the work is actually finished reports the unit complete too early. Keep handle lifetime tied exactly to the work it represents.

Note

Because adding a task raises the maximum immediately, the bar can appear to “jump back” when many tasks are enqueued faster than they complete. This is expected in the current implementation.