Containers

Structural nodes that arrange children — stacks, tables, and lists. Note there is no DocraftLoomForeach node: <Foreach> is expanded away during tree building (see Craft Language Parser), not represented in the node tree at all.

DocraftLoomLayoutContainer

Shared base for Rectangle/VStack/HStack — factors out spacing() and the CSS-margin-collapsing gap resolution between adjacent children (see DocraftLoomNode::margin() in Node Tree — Base & Text).

class DocraftLoomLayoutContainer : public docraft::loom::nodes::DocraftLoomShape

Abstract base for loom nodes that stack children with a gap between each pair of them and can optionally paint a background/border behind that stack.

Factors out what DocraftLoomRectangle, DocraftLoomVStack, and DocraftLoomHStack all need identically &#8212; spacing()/set_spacing(), plus style()/edit_style() inherited from DocraftLoomShape &#8212; so those three don’t each duplicate the same getter/setter pairs. Never instantiated directly; each subclass picks its own default spacing (Rectangle and VStack want visible breathing room by default, HStack’s shrink-to-fit columns don’t).

Subclassed by docraft::loom::nodes::DocraftLoomHStack, docraft::loom::nodes::DocraftLoomRectangle, docraft::loom::nodes::DocraftLoomVStack

Public Functions

~DocraftLoomLayoutContainer() override = default
float spacing() const
void set_spacing(float spacing)
virtual float resolve_outer_margin(const DocraftLoomNode &node, bool leading)

The gap this container must reserve outside its first (leading=true) or last (leading=false) child &#8212; that child’s own edge margin, with no sibling on that side to combine it with via resolve_child_gap().

0 if node has no children. Default reads the vertical edges (top/bottom), shared as-is by Rectangle/VStack; DocraftLoomHStack overrides this with its own (left/right) edges.

float effective_padding() const

The padding actually used for measurement/layout.

Public Static Functions

static float resolve_child_gap(float container_spacing, float margin_a, float margin_b)

The gap actually placed between two adjacent children, given the two touching edges (e.g.

child A’s bottom margin and child B’s top margin for a vertical stack, or A’s right and B’s left for a horizontal one).

Public Static Attributes

static constexpr float kDefaultPadding = 10.0F

Default inset (points) applied to padding() by the constructor below, so a Rectangle/VStack/HStack that paints a border/background doesn’t have its children’s content sit flush against that border unless the craft document explicitly overrides it via a padding attribute (set_padding()).

DocraftLoomRectangle

<Rectangle> — a DocraftLoomLayoutContainer with explicit width/height that stacks children top-to-bottom, plus background/border/padding (via DocraftLoomShape, see Shapes).

class DocraftLoomRectangle : public docraft::loom::nodes::DocraftLoomLayoutContainer

Represents a rectangular node in the Docraft Loom structure.

DocraftLoomRectangle is a specific implementation of DocraftLoomLayoutContainer that encapsulates properties and behavior for a rectangular shape. It supports visitor-based operations, background/border styling and inter-child spacing (both inherited from DocraftLoomLayoutContainer), and can hold children (inherited from DocraftLoomNode) that are laid out inside it, padded by padding() (also inherited from DocraftLoomNode &#8212; every node type has it, not just Rectangle).

Subclassed by docraft::loom::nodes::DocraftLoomCanvas

Public Functions

DocraftLoomRectangle()
~DocraftLoomRectangle() override = default
virtual void accept(loom::interfaces::DocraftLoomIVisitor &visitor) override
float width() const
void set_width(float width)
float height() const
void set_height(float height)

DocraftLoomVStack / DocraftLoomHStack

<Layout orientation="vertical"|"horizontal"> — stack children top-to- bottom or left-to-right. Only HStack supports weights (proportional column sizing); a vertical Layout’s weights attribute is a no-op.

class DocraftLoomVStack : public docraft::loom::nodes::DocraftLoomLayoutContainer

Loom node that stacks its children vertically (top-to-bottom).

During the measure pass, width = max child width and height = sum of child heights plus spacing between each pair of adjacent children (both spacing() and the optional background/border style() are inherited from DocraftLoomLayoutContainer &#8212; this lets <Header>/<Body>/<Footer> sections, built as a DocraftLoomVStack by DocraftLoomTreeBuilder::build_section, keep supporting background_color/border_color/border_width without needing DocraftLoomRectangle’s unrelated width_/height_/padding_ fields). During the layout pass, each child is placed below the previous one.

Public Functions

DocraftLoomVStack()
~DocraftLoomVStack() override = default
virtual void accept(interfaces::DocraftLoomIVisitor &visitor) override
class DocraftLoomHStack : public docraft::loom::nodes::DocraftLoomLayoutContainer

Loom node that places its children horizontally (left-to-right).

During the measure pass, height = max child height and width = sum of child widths plus spacing between each pair of adjacent children (both spacing() and the optional background/border style() are inherited from DocraftLoomLayoutContainer). During the layout pass, each child is placed to the right of the previous one, using its own natural width &#8212; unless weights() is non-empty, in which case the available content width is instead divided among children by weight (missing/non-positive entries default to 1.0, i.e. equal/homogeneous division), mirroring DocraftLoomTable’s column_weights.

Public Functions

DocraftLoomHStack()
~DocraftLoomHStack() override = default
virtual void accept(interfaces::DocraftLoomIVisitor &visitor) override
void set_weights(std::vector<float> weights)

Sets per-child weights used to divide the available content width.

Empty (the default) keeps today’s shrink-to-fit behavior, where each child simply gets its own natural width.

const std::vector<float> &weights() const
std::vector<float> resolve_horizontal_child_gaps(const DocraftLoomNode &node, float container_spacing)

DocraftLoomLayoutContainer::resolve_child_gap() applied to every adjacent pair of node’s children at once, using each child’s right/left margin (this is the horizontal-stacking counterpart of the vertical, per-pair calls Rectangle/VStack make directly)

virtual float resolve_outer_margin(const DocraftLoomNode &node, bool leading) override

The gap this container must reserve outside its first (leading=true) or last (leading=false) child &#8212; that child’s own edge margin, with no sibling on that side to combine it with via resolve_child_gap().

0 if node has no children. Default reads the vertical edges (top/bottom), shared as-is by Rectangle/VStack; DocraftLoomHStack overrides this with its own (left/right) edges.

DocraftLoomTable / DocraftLoomTableCell

<Table> — a grid of cells with column weights, optional per-cell background, title cells (painted last, over dividers), and split_after_row() support for pagination across pages. Cell content must be DocraftLoomText or DocraftLoomImage; absolute positioning inside a cell throws InvalidInputException at layout time.

class DocraftLoomTable : public docraft::loom::nodes::DocraftLoomNode

Table node: a grid of DocraftLoomTableCell nodes.

There is no separate “header row/column” concept &#8212; a cell may be marked is_title() (a property on the cell itself), which only affects draw order in Rendering (title cells paint last, over any dividers). Measure/Layout treat every cell uniformly regardless of is_title &#8212; this is what lets the same table represent both a “column headers” (title row) and a “row labels” (title column) shape with one code path.

Column-width resolution is computed by the layout engine (DocraftLoomLayoutProcessor) and written into each cell’s own frame.size &#8212; the table itself holds no separate width/height cache, mirroring how every other container (VStack/HStack/Rectangle) derives its rendering geometry from its children’s own LayoutBox rather than a parallel cache.

Public Functions

DocraftLoomTable() = default
~DocraftLoomTable() override = default
virtual void accept(loom::interfaces::DocraftLoomIVisitor &visitor) override
void add_row(std::vector<std::shared_ptr<DocraftLoomTableCell>> cells)
Throws:

exception::InvalidInputException – if any cell is null, or if the row’s column count doesn’t match previously added rows.

int row_count() const
int column_count() const
std::shared_ptr<DocraftLoomTableCell> cell(int row, int column) const
void set_column_weights(std::vector<float> weights)
const std::vector<float> &column_weights() const
void set_default_cell_background(const DocraftColor &color)
const std::optional<DocraftColor> &default_cell_background() const
float baseline_offset() const
void set_baseline_offset(float baseline_offset)
float padding() const

Outer spacing around the whole table (all four sides), mirroring how DocraftLoomRectangle’s own padding() insets its children from its border &#8212; here there’s no border to speak of, so it simply keeps the grid from sitting flush against whatever precedes/follows the table (or the page edge).

Wired to the common padding craft-language attribute like any other node that exposes a setter (see DocraftLoomTreeBuilder::apply_common_attributes).

void set_padding(float padding)
std::shared_ptr<DocraftLoomTable> split_after_row(int row_index, bool repeat_header_rows = true)

Splits off rows [row_index, row_count()) into a new table (mirrors legacy’s DocraftTable::split_after_row), for use when a table doesn’t fit on one page.

Column weights/default background/baseline offset are copied onto the remainder. If repeat_header_rows is true, a leading contiguous run of all-title rows in this table (before row_index) is cloned onto the front of the remainder too, so a header row keeps repeating on the continuation.

Returns:

The remainder table, or nullptr if row_index is 0 or >= row_count() (nothing to split).

Public Static Attributes

static constexpr float kCellPaddingX = 2.5F
static constexpr float kCellPaddingY = 2.5F
class DocraftLoomTableCell : public docraft::loom::nodes::DocraftLoomNode

A single table cell &#8212; a node like any other.

Its content is just its child (set via set_content(), which enforces the same Text/Image-only restriction as legacy tables). background/explicit_width/is_title are properties of the cell itself, not of the table.

Public Functions

DocraftLoomTableCell() = default
~DocraftLoomTableCell() override = default
virtual void accept(loom::interfaces::DocraftLoomIVisitor &visitor) override
void set_content(std::shared_ptr<DocraftLoomNode> content)

Sets the cell’s content, replacing any existing child.

Throws:

exception::InvalidInputException – if content is neither a DocraftLoomText nor a DocraftLoomImage.

std::shared_ptr<DocraftLoomNode> content()
const std::optional<DocraftColor> &background() const
void set_background(const DocraftColor &color)
std::optional<float> explicit_width() const
void set_explicit_width(float width)
bool is_title() const
void set_is_title(bool is_title)

DocraftLoomList

<List>/<UList> — ordered (number/roman) or unordered (dash/star/ circle/box) markers; items are plain DocraftLoomText children.

class DocraftLoomList : public docraft::loom::nodes::DocraftLoomNode

Loom node representing a list.

Items are DocraftLoomText children (added via the inherited add_child()); each item gets a Marker computed during Measure (text/kind/width) and positioned during Layout.

Public Functions

DocraftLoomList() = default
~DocraftLoomList() override = default
virtual void accept(loom::interfaces::DocraftLoomIVisitor &visitor) override
ListKind kind() const
void set_kind(ListKind kind)
OrderedListStyle ordered_style() const
void set_ordered_style(OrderedListStyle style)
UnorderedListDot unordered_dot() const
void set_unordered_dot(UnorderedListDot dot)
bool marker_is_box() const
std::string marker_text_for_index(int index) const

Returns the marker text for a 0-based item index (e.g.

“1.”, “IV.”, “*”), mirroring legacy’s DocraftList::prefix_for_index/roman_for. Box markers have no text (an empty string), the box itself is drawn instead.

const std::vector<Marker> &markers() const
std::vector<Marker> &edit_markers()
float marker_gap() const
struct Marker

Public Types

enum class Kind

Values:

enumerator kText
enumerator kBox

Public Members

std::string text
Position position
Kind kind = Kind::kText
float width = 0.0F