docs: a user guide covering getting started, architecture, embedding, data, interaction, styling and testing
This commit is contained in:
1 parent
d03f9ce51a
commit
b7d0f901cc
7 files changed
+1082
No files matched your search
@@ -0,0 +1,68 @@
|
||||
# Architecture
|
||||
|
||||
`plot` is one library, `plot_core`, plus optional adapter targets. The public headers are
|
||||
grouped into seven directories, and the umbrella header `include/plot/plot.hpp` includes
|
||||
them in this order:
|
||||
|
||||
```
|
||||
core / math → gl → data → render → plot → input
|
||||
```
|
||||
|
||||
with the host adapters (`adapters/glfw`, `adapters/imgui`, `adapters/qt6`, `adapters/gtk4`)
|
||||
built on top. This page says what each layer owns and the rules the build enforces.
|
||||
|
||||
## What each layer owns
|
||||
|
||||
| layer | directory | owns |
|
||||
|---|---|---|
|
||||
| `core` | `include/plot/core/`, `src/core/` | the vocabulary: `f32`/`f64`/`u32`/`usize`, `kInvalid`, `Range`, `Rect`, `Color`, `Span`, and `Status`/`ErrorCode` for fallible operations. |
|
||||
| `math` | `include/plot/math/`, `src/math/` | `Vec2`, `Mat3`, and `Transform` — the data↔pixel affine mapping, including the log-axis handling and its invertibility guarantee. |
|
||||
| `gl` | `include/plot/gl/`, `src/gl/` | a hand-written OpenGL surface: enumerator typedefs, the entry-point table `plot::gl::load()` fills, `plot::gl::caps()`, and the move-only RAII wrappers (`gl::Buffer`, `VertexArray`, `Program`, `Texture`, `Framebuffer`, `Fence`). No GL loader library is used. |
|
||||
| `data` | `include/plot/data/`, `src/data/` | the sample stores: the `Series` interface, `ArraySeries`, `StreamSeries`, `RingBuffer`, and the min/max LOD `MinMaxPyramid`. |
|
||||
| `render` | `include/plot/render/`, `src/render/` | presentation: `Style`, the `Renderer`, the text machinery (`TextBackend`, `TextAtlas`, `EmbeddedMonoFont`), and the shader/program/buffer/vertex-array primitives. |
|
||||
| `plot` | `include/plot/plot/`, `src/plot/` | the scene model: `Plot`, `Figure`, and the primitives they own — `Axis`, `Trace`, `Cursor`, `Region`, `Measure`, `Legend`, `Crosshair`, `Annotation`, `Grid`, `Ticks`. Pure CPU state, no GL. |
|
||||
| `input` | `include/plot/input/`, `src/input/` | `Controller` and the host-neutral event types (`PointerEvent`, `WheelEvent`, `KeyEvent`); turns events into gestures. |
|
||||
| adapters | `adapters/*/` | one per host: they own the window/context/event loop and translate their toolkit's events into `input` events. |
|
||||
|
||||
## The dependency rules
|
||||
|
||||
- **`plot_core` is third-party-free.** Its `CMakeLists.txt` links only
|
||||
`${CMAKE_DL_LIBS}`, and the public headers under `include/plot/` include no third-party
|
||||
header. The one exception is the optional `plot::font_ttf` target, which compiles the
|
||||
vendored `third_party/stb_truetype.h` (stb_truetype v1.26, public domain) in its own
|
||||
object library `plot_stb_truetype`, whose include directory is `PRIVATE` — so nothing
|
||||
else in the build, and no consumer, can reach it by accident. `PLOT_BUILD_TTF_FONT`
|
||||
defaults to on exactly when the vendored header is present.
|
||||
- **Every public header compiles standalone, and `plot.hpp` includes every one of them.**
|
||||
`tests/CMakeLists.txt` generates one translation unit per header (globbed, so a new
|
||||
header is picked up automatically), builds an umbrella TU, and registers ctest cases
|
||||
(`plot_headers_self_contained`, `plot_umbrella_covers_public_headers`,
|
||||
`plot_umbrella_check`) that fail the build if either rule breaks.
|
||||
- **The umbrella stops at the library.** It never includes an adapter header, so
|
||||
`#include <plot/plot.hpp>` cannot drag in GLFW, ImGui, Qt or GTK. The adapter headers are
|
||||
reached as `<glfw/glfw_host.hpp>`, `<imgui/imgui_plot.hpp>`, `<qt6/qt_plot_widget.hpp>`
|
||||
and `<gtk4/gtk_plot_area.hpp>`.
|
||||
- **The renderer never owns the context or the event loop.** `Renderer` never creates,
|
||||
binds or resizes a framebuffer: `begin_frame(fb_w, fb_h, viewport_px)` draws into
|
||||
whatever framebuffer is bound, clears exactly the given rectangle (scissored, so a host
|
||||
that painted the rest of its surface keeps it), and `end_frame()` turns the GL state it
|
||||
moved back off. The renderer also never sees a pointer, a button or a modifier — it draws
|
||||
the handles the plot reports as hot, and only a host that drives the plot with an
|
||||
`input::Controller` ever makes anything hot. Owning the window, the context and the loop
|
||||
is the adapter's job (or, for a library user, the application's).
|
||||
|
||||
One direction is worth stating precisely, because it is the one place the layer order is
|
||||
not a strict include chain: `Renderer` (in `render/`) includes `plot/plot.hpp` and
|
||||
`plot/figure.hpp`, because drawing *is* being handed a `Plot` or a `Figure` to draw. The
|
||||
`plot` layer names only `render`'s value types — `render::Style` and
|
||||
`render::TextBackend` — and never names `Renderer`. So the runtime direction is
|
||||
"the renderer knows the plot, the plot does not know the renderer".
|
||||
|
||||
## The design record
|
||||
|
||||
The specifications and implementation plans — the requirements, the numbered spec sections
|
||||
this documentation sometimes refers to, and the reasoning behind decisions — live under
|
||||
[`docs/superpowers/`](superpowers/) (`specs/` and `plans/`). That tree is the project's
|
||||
design record, not user documentation: it is where a decision is argued, not where the
|
||||
library is explained. This `docs/` guide and [docs/coverage.md](coverage.md) are the
|
||||
user-facing documents.
|
||||
Reference in new issue
Block a user