feat(plot): Figure with stacked rows and a synchronised x axis

This commit is contained in:
Martino Ferrari committed 2026-09-28 14:42:17 +02:00
1 parent 7cc06f07f5
commit 8f1e60a105
11 files changed
+1665 -24

No files matched your search

+24 -1
View File
@@ -42,7 +42,10 @@ struct PlotLayout {
Rect x_title_area;
/// Left strip width. The default is used when no text backend has been set.
f32 y_axis_width = 56.0f;
/// Bottom strip height. The default is used when no text backend has been set.
/// Bottom strip height. The default is used when no text backend has been set, and
/// it is 0.0f when the strip is not reserved at all -- see
/// `Plot::set_x_label_strip()`, which is how a row of a `Figure` hands the band to
/// the figure's one shared axis.
f32 x_axis_height = 22.0f;
/// Width of `y_title_area` and height of `x_title_area`, both 0.0f when nothing
/// is reserved. Every titled axis of a direction gets its own text line inside
@@ -131,6 +134,24 @@ class Plot {
/// The scale the last layout was computed at. 1.0 until a host says otherwise.
f32 ui_scale() const noexcept { return style_.ui_scale; }
/// Whether `layout()` reserves the bottom x label strip -- and, with it, the x
/// title strip: a title is the labels' caption and goes where they do.
///
/// True by default, which is what a plot drawn on its own has always been. A
/// `Figure` turns it off on every row while it draws one shared x axis under its
/// last row (see `Figure::set_x_labels_only_on_bottom()`): the strip is not
/// merely left blank, it is not reserved at all, so such a row's `axes` reaches
/// the row rect's bottom edge and the row gives the band to the figure's shared
/// axis instead of growing a second, duplicate one. Nothing else about the row
/// changes -- its ticks still refresh and its grid still builds, because the
/// tick list is what the shared axis and the grid are drawn from, not the strip.
///
/// The plot it belongs to draws no x tick labels while it is off (their strip
/// has no height left to hold them); whoever turned it off is the one that puts
/// them somewhere -- `Renderer::draw(Figure&)` draws them in the figure's strip.
void set_x_label_strip(bool on) noexcept { x_label_strip_ = on; }
bool x_label_strip() const noexcept { return x_label_strip_; }
/// The font layout() measures tick labels with. Borrowed, not owned, and may be
/// null -- then the label areas fall back to PlotLayout's defaults and no string
/// is measured: a plot with no renderer lays out with whatever the host sets
@@ -534,6 +555,8 @@ class Plot {
render::Style style_{};
const render::TextBackend* text_ = nullptr;
Legend legend_{};
/// Whether the bottom x label strip is reserved at all; see set_x_label_strip().
bool x_label_strip_ = true;
/// Which handles a pointer is on, published by the input layer (see HotHandles).
HotHandles hot_{};