Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/skills/craft-language/references/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ background/border.
| `background_color` | color | fully transparent |
| `border_color` | color | fully transparent |
| `border_width` | float | `1.0` (invisible unless `border_color` has alpha) |
| `border_style` | enum: `solid`, `dashed` | `solid` |
| `width`, `height` | float | `0` = shrink-to-fit / use incoming width, not literally zero |
| `padding` | float (common) | `10.0`, but collapses to `0` if the rectangle paints neither fill nor stroke |

Expand Down Expand Up @@ -146,6 +147,7 @@ Rectangle/Text).
| Attribute | Type | Notes |
|---|---|---|
| `background_color`, `border_color`, `border_width` | color/color/float | shared shape style |
| `border_style` | enum: `solid`, `dashed` | default `solid`; applies to the arc too, when present |
| `radius` | float | true circle; mutually exclusive with `width`/`height` |
| `width`, `height` | float | inscribes an ellipse in that bounding box; both required together |
| `start_x`, `start_y`, `finish_x`, `finish_y` | float | arc endpoints, all four or none |
Expand All @@ -171,6 +173,7 @@ direction — swapping them picks the complementary arc.
| Attribute | Type | Notes |
|---|---|---|
| `background_color`, `border_color`, `border_width` | color/color/float | |
| `border_style` | enum: `solid`, `dashed` | default `solid` |
| `points` | string, space-separated `x,y` tokens | **must be exactly 3 points**, else throws |

`points="0,0 50,0 25,50"`. Y-down offsets from the node's own frame origin.
Expand All @@ -191,6 +194,7 @@ shape node — no `background_color` (fill) at all.
| `points` | space-separated `x,y` tokens | **minimum 2 points**, else throws |
| `border_color` | color | black |
| `border_width` | float | `1.0` |
| `border_style` | enum: `solid`, `dashed` | `solid` |

```xml
<CurveLine points="0,0 20,40 60,10" border_color="blue" border_width="2"/>
Expand All @@ -204,6 +208,7 @@ shape node — no `background_color` (fill) at all.
| `x2`, `y2` | float | `(100, 0)` |
| `border_color` | color | black |
| `border_width` | float | `1.0` |
| `border_style` | enum: `solid`, `dashed` | `solid` |

## `<List>` / `<UList>`

Expand Down
31 changes: 30 additions & 1 deletion doc/source/craft_language/shapes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ Shapes
======

Docraft supports several geometric shape elements. All shapes share
``background_color``, ``border_color``, and ``border_width`` attributes.
``background_color``, ``border_color``, ``border_width``, and ``border_style``
attributes. ``<Line>`` and ``<CurveLine>`` are stroke-only (no ``background_color``) but
share the same ``border_color``/``border_width``/``border_style`` trio.

``border_style`` accepts ``solid`` (the default) or ``dashed``, and applies to every
shape's border as well as to ``<Line>``/``<CurveLine>``:

.. code-block:: xml

<Rectangle width="200" height="100" border_color="black" border_width="1"
border_style="dashed"/>
<Line x1="0" y1="0" x2="200" y2="0" border_color="black" border_style="dashed"/>

Rectangle
---------
Expand Down Expand Up @@ -33,6 +44,9 @@ Rectangle
* - ``border_width``
- float
- Stroke width in points (default ``1``).
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``).

Circle
------
Expand Down Expand Up @@ -76,6 +90,9 @@ the center is ``(x + width/2, y + height/2)``.
* - ``border_width``
- float
- Stroke width in points.
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``). Applies to the arc too, when present.

The two sizing methods are exclusive on purpose, and every violation is a parse error
rather than a silently misdrawn shape:
Expand Down Expand Up @@ -158,6 +175,9 @@ Triangle
* - ``border_width``
- float
- Stroke width in points.
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``).

Line
----
Expand Down Expand Up @@ -201,6 +221,9 @@ they are clipped at its bounds.
* - ``border_width``
- float
- Stroke width in points.
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``).

.. _craft-canvas:

Expand Down Expand Up @@ -259,6 +282,9 @@ curved counterpart of ``<Line>``, and what a spline chart's series line is made
* - ``border_width``
- float
- Stroke width in points.
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``).

The curve **interpolates**: it passes exactly through every point rather than near
them. With exactly 2 points it degenerates to a straight segment, which is why 2 is a
Expand Down Expand Up @@ -304,4 +330,7 @@ an open curve through the same points see :ref:`CurveLine <craft-curveline>` abo
* - ``border_width``
- float
- Stroke width in points.
* - ``border_style``
- ``solid`` | ``dashed``
- Stroke pattern (default ``solid``).

4 changes: 4 additions & 0 deletions docraft/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ set(DOCRAFT_SOURCES
include/docraft/loom/nodes/docraft_loom_rectangle.h
src/docraft/loom/nodes/docraft_loom_canvas.cc
include/docraft/loom/nodes/docraft_loom_canvas.h
include/docraft/loom/nodes/docraft_loom_line_style.h
src/docraft/loom/nodes/docraft_loom_stroked_line.cc
include/docraft/loom/nodes/docraft_loom_stroked_line.h
include/docraft/loom/nodes/docraft_loom_shape_style.h
src/docraft/loom/nodes/docraft_loom_shape.cc
include/docraft/loom/nodes/docraft_loom_shape.h
Expand Down Expand Up @@ -141,6 +144,7 @@ set(DOCRAFT_SOURCES
include/docraft/craft/parser/docraft_craft_enum_parsers.h
src/docraft/craft/parser/docraft_shape_parser_utils.cc
include/docraft/craft/parser/docraft_shape_parser_utils.h
include/docraft/craft/parser/docraft_parsed_line_style.h
include/docraft/craft/parser/docraft_parser.h
src/docraft/craft/parser/docraft_rectangle_parser.cc
src/docraft/craft/parser/docraft_chart_parser.cc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ namespace docraft::backend {
*/
virtual void set_line_width(float thickness) const = 0;

/**
* @brief Sets the dash pattern used for subsequent line/curve stroking:
* alternating on/off segment lengths in points, starting with an "on" segment.
* An empty pattern resets to a solid (continuous) line.
* @param pattern The on/off segment lengths, in points.
*/
virtual void set_line_dash_pattern(const std::vector<float>& pattern) const = 0;

/**
* @brief Draws a line between two points using the current stroke settings.
* @param x1 The x-coordinate of the line start.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ namespace docraft::backend::pdf {
*/
void set_line_width(float thickness) const override;

/**
* @brief Sets the dash pattern used for line/curve stroking via libharu's
* HPDF_Page_SetDash. An empty pattern resets to a solid line (num_dash=0).
*/
void set_line_dash_pattern(const std::vector<float>& pattern) const override;

/**
* @brief Draws a line segment between two points.
*/
Expand Down
14 changes: 14 additions & 0 deletions docraft/include/docraft/craft/docraft_craft_language_tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,14 @@ namespace docraft::craft {
constexpr string kBackgroundColor = "background_color";
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";

}
namespace circle::attribute {
constexpr string kBackgroundColor = "background_color";
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";
constexpr string kRadius = "radius";
// Arc endpoints: given as points, all four together or none.
constexpr string kStartX = "start_x";
Expand All @@ -268,6 +270,7 @@ namespace docraft::craft {
constexpr string kBackgroundColor = "background_color";
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";
constexpr string kPoints = "points";
}
namespace line::attribute {
Expand All @@ -277,17 +280,20 @@ namespace docraft::craft {
constexpr string kY2 = "y2";
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";
}
namespace polygon::attribute {
constexpr string kBackgroundColor = "background_color";
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";
constexpr string kPoints = "points";
}
// No background_color: an open curve has no interior to fill.
namespace curve_line::attribute {
constexpr string kBorderColor = "border_color";
constexpr string kBorderWidth = "border_width";
constexpr string kBorderStyle = "border_style";
constexpr string kPoints = "points";
}

Expand Down Expand Up @@ -361,4 +367,12 @@ namespace docraft::craft {
constexpr string kVertical = "vertical";
}

/**
* @brief `border_style` string literals for line-like elements and shape borders.
*/
namespace line_style {
constexpr string kSolid = "solid";
constexpr string kDashed = "dashed";
}

}
6 changes: 2 additions & 4 deletions docraft/include/docraft/craft/parser/docraft_circle_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "docraft/docraft_lib.h"

#include "docraft/craft/i_docraft_parser.h"
#include "docraft/craft/parser/docraft_parsed_line_style.h"

namespace docraft::craft::parser {
/**
Expand All @@ -31,11 +32,8 @@ namespace docraft::craft::parser {
* used a width/height bounding box); `docraft::loom::nodes::DocraftLoomCircle` only
* ever has a single radius.
*/
struct ParsedCircleData
struct ParsedCircleData : ParsedShapeStyleData
{
std::optional<std::string> background_color;
std::optional<std::string> border_color;
std::optional<float> border_width;
std::optional<float> radius;
/**
* @brief Arc endpoints, as points in the node's own box. All four are required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "docraft/docraft_lib.h"

#include "docraft/craft/i_docraft_parser.h"
#include "docraft/craft/parser/docraft_parsed_line_style.h"
#include "docraft/docraft_position.h"

namespace docraft::craft::parser {
Expand All @@ -34,11 +35,9 @@ namespace docraft::craft::parser {
* `<Polygon>` this element is stroke-only by construction rather than by
* convention.
*/
struct ParsedCurveLineData
struct ParsedCurveLineData : ParsedStrokeStyleData
{
std::vector<docraft::Position> points;
std::optional<std::string> border_color;
std::optional<float> border_width;
};

/**
Expand Down
5 changes: 2 additions & 3 deletions docraft/include/docraft/craft/parser/docraft_line_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@
#include "docraft/docraft_lib.h"

#include "docraft/craft/i_docraft_parser.h"
#include "docraft/craft/parser/docraft_parsed_line_style.h"

namespace docraft::craft::parser {
/**
* @brief Tag-specific payload parsed from a `<Line>` element.
*/
struct ParsedLineData
struct ParsedLineData : ParsedStrokeStyleData
{
std::optional<float> x1;
std::optional<float> y1;
std::optional<float> x2;
std::optional<float> y2;
std::optional<std::string> border_color;
std::optional<float> border_width;
};

/**
Expand Down
57 changes: 57 additions & 0 deletions docraft/include/docraft/craft/parser/docraft_parsed_line_style.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2026 Matteo Cadoni (https://github.com/cadons)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <optional>
#include <string>

namespace docraft::craft::parser {
/**
* @brief Stroke style for line-like elements (`<Line>`/`<CurveLine>`) and shape
* borders (`<Rectangle>`/`<Circle>`/`<Triangle>`/`<Polygon>`), duplicated from
* (rather than shared with) loom's own `docraft::loom::nodes::DocraftLineStyle` --
* see `ParsedTextStyle` for the same "duplicate a tiny enum and translate"
* rationale.
*/
enum class ParsedLineStyle
{
kSolid,
kDashed
};

/**
* @brief Border styling shared by every stroke-only, line-like element
* (`<Line>`/`<CurveLine>`). Base struct rather than duplicating the same three
* fields on each `Parsed*Data`.
*/
struct ParsedStrokeStyleData
{
std::optional<std::string> border_color;
std::optional<float> border_width;
std::optional<ParsedLineStyle> border_style;
};

/**
* @brief Background+border styling shared by every fillable shape element
* (`<Rectangle>`/`<Circle>`/`<Triangle>`/`<Polygon>`). Extends
* `ParsedStrokeStyleData` with the fill color those elements additionally support.
*/
struct ParsedShapeStyleData : ParsedStrokeStyleData
{
std::optional<std::string> background_color;
};
} // namespace docraft::craft::parser
6 changes: 2 additions & 4 deletions docraft/include/docraft/craft/parser/docraft_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,14 @@

#include "docraft/craft/docraft_craft_parsed_element.h"
#include "docraft/craft/i_docraft_parser.h"
#include "docraft/craft/parser/docraft_parsed_line_style.h"

namespace docraft::craft::parser {
/**
* @brief Tag-specific payload parsed from a `<Rectangle>` element.
*/
struct ParsedRectangleData
struct ParsedRectangleData : ParsedShapeStyleData
{
std::optional<std::string> background_color;
std::optional<std::string> border_color;
std::optional<float> border_width;
};

/**
Expand Down
10 changes: 10 additions & 0 deletions docraft/include/docraft/craft/parser/docraft_parser_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ namespace docraft::craft::parser::detail {
*/
ParsedTextAlignment parse_text_alignment(const std::string& alignment_str);

/**
* @brief Parses a `border_style` attribute value (e.g. "dashed") into a
* `ParsedLineStyle`. Shared by every line/shape-border parser (`Line`/`CurveLine`/
* `Rectangle`/`Circle`/`Triangle`/`Polygon`).
* @param style_str The raw attribute string.
* @return The parsed line style.
* @throws docraft::exception::InvalidInputException if the string is not a recognized style.
*/
ParsedLineStyle parse_line_style(const std::string& style_str);

/**
* @brief Trims leading/trailing whitespace (space, tab, newline, CR, form feed,
* vertical tab) from a string.
Expand Down
6 changes: 2 additions & 4 deletions docraft/include/docraft/craft/parser/docraft_polygon_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@
#include "docraft/docraft_position.h"

#include "docraft/craft/i_docraft_parser.h"
#include "docraft/craft/parser/docraft_parsed_line_style.h"

namespace docraft::craft::parser {
/**
* @brief Tag-specific payload parsed from a `<Polygon>` element.
*/
struct ParsedPolygonData
struct ParsedPolygonData : ParsedShapeStyleData
{
std::optional<std::string> background_color;
std::optional<std::string> border_color;
std::optional<float> border_width;
std::vector<docraft::Position> points;
};

Expand Down
Loading
Loading