Repository navigation
Development Architecture
How the GUI code is organised, and the rules that keep it that way.
Platemaker GUI is a cross-platform Qt 6 desktop application for comic artists. It puts what
libplatemaker does behind a visual interface:
- workspaces (
.platemaker.jsonfiles) and the projects (chapters) in them; - source pages as scrollable tile grids;
- the strip pipeline, with live progress;
- canvas profiles and margin-overlay templates; output profiles (format, slice size, JPEG options);
- the pipeline's two optional steps, authored on a continuous strip of the chapter: a project-wide colour grade, and text, balloons and artwork (strip editor).
The GUI is a thin shell. All domain logic — the pipeline, the data models, serialisation,
profile matching — lives in libplatemaker.
Qt GUI (this repository)
├── views, widgets, dialogs all QWidget-derived
├── background workers render worker, thumbnail loading
└── no domain logic
libplatemaker (shared library)
├── WorkspaceSerializer, CanvasProfileMatcher
├── Scaler, ScaledStrip, Slicer, MarginCropper, TemplateGenerator
└── ThumbnailCache, ImageIO, CancellationToken
| File | Holds |
|---|---|
mainwindow/mainwindow.cpp |
Construction, menu wiring, shortcuts |
mainwindow/workspace.cpp |
Open, save, close, recent files |
mainwindow/projects.cpp |
Creating, renaming, removing projects |
mainwindow/render.cpp |
Starting, monitoring and cancelling renders; the render gate |
mainwindow/renderbatch.cpp |
Refresh all projects (F6): one chapter after another |
mainwindow/profiles.cpp |
Canvas and output profile actions |
mainwindow/templates.cpp |
Template generation actions |
mainwindow/advisories.cpp |
The conditions this window observes, and the status bar that reports them |
mainwindow/fonts.cpp |
Tools → Fonts…: the workspace's own fonts and the ones its lettering misses |
mainwindow/package.cpp |
File → Export package… / Open package… |
mainwindow/about.cpp |
Version, authors and the manual, in one dialog |
Each folder under widgets/ holds one widget or dialog, with its .h, .cpp and .ui
together. The names say what they are; project/ is the only one large enough to be split, into
input.cpp and output.cpp for its two tabs.
There is exactly one Workspace, held by MainWindow. Widgets do not keep copies — they
read it live.
Project therefore stores a project index, not a reference or pointer to a ProjectItem.
That is deliberate: the workspace holds projects in a vector, so removing a lower-indexed project
shifts everything after it and would leave any stored reference dangling. An index can be
corrected instead, which is what setProjectIndex() exists for.
The corollary is that no widget may cache workspace data across an operation that could reallocate the vector.
Anything that changes workspace data marks the workspace modified, which surfaces as a * after
the filename in the title bar and is cleared by saving.
Widgets do not set that flag directly — Project emits projectModified() and MainWindow owns
the consequence. Any new code path that mutates workspace data has to emit it too, or the change
will be silently lost on exit.
| Operation | Mechanism | Notes |
|---|---|---|
| Render |
RenderWorker on its own thread |
Owns copies of its inputs; never touches the live workspace |
| Thumbnails | Per-tile background load |
ThumbnailCache is thread-safe |
| Cancellation | CancellationToken |
Atomic; checked between slices, so cancelling is cooperative rather than immediate |
Two rules hold the threading model together:
- A worker never touches a widget. Everything crosses back to the GUI thread as a queued signal.
-
A worker never touches the live workspace.
RenderWorkeris constructed with copies of everything it needs — inputs, profiles, output directory — so a render cannot race against the user editing the project underneath it. Its result is read back on the main thread when it finishes.
Slots that respond to a control are named for the event: onAddFiles(), onRenderClicked(),
onOutputProfileChanged(). Signals are named for what happened, in the past tense:
projectModified(), sliceSaved(), renderToggleRequested().
Connections use the pointer-to-member form (&Class::signal), never the string-based SIGNAL/
SLOT macros, so that a mismatch is a compile error rather than a silent runtime no-op.
- Tested on Windows 10/11 (MSVC + MSYS2 MinGW) and Ubuntu 22.04.
-
platemaker.dlland the libvips runtime DLLs are copied next to the executable by the CMake post-build step — no manual PATH setup needed. - Linux: the installed binary carries an RPATH (
$ORIGIN,$ORIGIN/../lib), whichqt_standard_project_setup()adds; noLD_LIBRARY_PATHneeded after install. - macOS: not tested yet.
-
The application is dark, whatever the OS is set to.
app/main.cppforces the dark colour scheme (QStyleHints::setColorScheme). Windows 11 keeps its nativewindows11style, which renders dark from that scheme; Windows 10 and Linux get Fusion with an explicit dark palette, because the Windows 10 native style has no dark theme and leaves controls, popups and menus light.PM_FORCE_FUSION(an environment variable) previews the Fusion path on Windows 11. -
New widgets carry no colour stylesheet: they take their colours from that palette, so they look the
same on both paths. Several older dialogs still hardcode a dark stylesheet in their
.ui; that is the pattern not to copy. - Dialog buttons: standard
QDialogButtonBoxwith Ok / Cancel. - Destructive actions (delete profile, remove project): require a
QMessageBox::questionconfirmation. - Errors from libplatemaker (pipeline, serialiser): shown as
QMessageBox::critical. - Progress:
QProgressBarin the Action dock, 0–100 (percent of output slices written).
See also: Building · Contributing · Concepts
Platemaker GUI 1.4.3 · GPL-3.0 · Application repository · libplatemaker · Report an issue
Development pages synced to code commit 1331e01 (2026-10-04).
Overview
Manual
- Manual overview
- Installation
- Quick start
- Concepts
- Main window
- Workspaces
- Projects
- Canvas profiles
- Templates
- Output profiles
- Rendering
- File statuses
- Menu reference
- Troubleshooting
Comic production
Development
- Overview
- Environment
- Building
- Architecture
- Main window
- Workflows
- Releasing
- Contributing
- Windows hardening
Strip editor