Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
svg_fragment.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4
5// SVG fragment handles.
6//
7// A faithful design port renders one big SVG document (the frame) via
8// Canvas::draw_svg, then needs to restyle or move ONE sub-tree of it on demand:
9// brighten the hovered control, dim a bypassed one, drop a reorder ghost, spin a
10// meter needle. Re-exporting a fresh SVG per state is wasteful; mutating the live
11// document (the wrap_needle_rotation model in design_frame_view.cpp) works for
12// the one dragged control but doesn't compose for overlays that must paint ON TOP
13// of the already-drawn frame with their own transform/opacity/recolor.
14//
15// The fragment-handle primitive is the composable answer: extract a named
16// sub-tree once (by a unique marker substring — typically a path `d`, the same
17// handle wrap_needle_rotation keys on — reusing the SVG-as-string model the
18// suppress_svg_* helpers already establish), then build a STANDALONE mini-document
19// that shares the source's `<svg …>` header (so coordinates line up 1:1 with the
20// full render) containing only that fragment, wrapped in an optional
21// transform + opacity and recolored. Drawing that mini-document through the SAME
22// draw box the full frame used composites the restyled fragment exactly over its
23// original position.
24//
25// These are pure string/geometry helpers with no Canvas or GPU dependency, so the
26// extraction + document-build + transform math is fully unit-testable in a
27// headless, Skia-free build; DesignFrameView layers the draw_svg call on top.
28namespace pulp::view {
29
30// An affine restyle applied to a fragment: a translate, then a rotate (degrees,
31// about a pivot), then a uniform scale (about the same pivot). Emitted as an SVG
32// `transform` attribute in SOURCE (SVG) coordinates — the fragment mini-document
33// is drawn through the same panel→view fit as the frame, so the transform reads in
34// the design's own coordinate space, matching wrap_needle_rotation's convention.
36 float dx = 0.0f, dy = 0.0f;
37 float rotate_deg = 0.0f;
38 float scale = 1.0f;
39 float pivot_x = 0.0f, pivot_y = 0.0f;
40
42 bool is_identity() const;
43
47 std::string to_svg_transform() const;
48};
49
50// Extract the single SVG element that CONTAINS `marker` (a unique substring, e.g.
51// a path's `d` value). Returns the element's full source text — a self-closing
52// `<… />` element verbatim, or a `<tag …>…</tag>` container with its matching
53// (depth-balanced) close tag. Returns "" if the marker isn't found or the element
54// is malformed. Mirrors the rfind('<', …) element-start model wrap_needle_rotation
55// uses, extended to depth-match a container close.
56std::string extract_svg_fragment(const std::string& svg, const std::string& marker);
57
58// Return the source document's opening `<svg …>` tag verbatim (through its '>'),
59// which carries width/height/viewBox/xmlns. "" if there is no `<svg` header. The
60// fragment mini-document reuses this so its coordinate space is identical to the
61// source's.
62std::string svg_open_tag(const std::string& svg);
63
64// Recolor a fragment: replace the VALUE of every `fill="…"` (and, when
65// `include_stroke`, `stroke="…"`) attribute whose current value is not "none"
66// with `hex` (a "#RRGGBB" string). Leaves `fill="none"` alone so an outline-only
67// element stays an outline. Returns the recolored fragment. A no-op when `hex` is
68// empty. Used for hover-brighten / disabled-desaturate tinting.
69std::string recolor_svg_fragment(std::string fragment, const std::string& hex,
70 bool include_stroke = false);
71
72// Build a standalone `<svg>` document that renders ONLY `fragment`, transformed by
73// `xform`, composited at `opacity` (0..1), and optionally recolored to `recolor_hex`.
74// `source_svg` supplies the shared `<svg …>` header so the fragment lands at the
75// same coordinates as the full frame. When the transform is identity, opacity is
76// >= 1, and no recolor is requested, the fragment is emitted unwrapped. Returns ""
77// if `source_svg` has no `<svg` header or `fragment` is empty.
78std::string build_svg_fragment_document(const std::string& source_svg,
79 const std::string& fragment,
80 const FragmentTransform& xform,
81 float opacity = 1.0f,
82 const std::string& recolor_hex = {});
83
84} // namespace pulp::view
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
std::string recolor_svg_fragment(std::string fragment, const std::string &hex, bool include_stroke=false)
std::string build_svg_fragment_document(const std::string &source_svg, const std::string &fragment, const FragmentTransform &xform, float opacity=1.0f, const std::string &recolor_hex={})
@ opacity
Definition css_animation.hpp:119
std::string extract_svg_fragment(const std::string &svg, const std::string &marker)
std::string svg_open_tag(const std::string &svg)
Definition svg_fragment.hpp:35
std::string to_svg_transform() const
The transform="…" attribute VALUE (without the transform= / quotes), composed outermost-first as SVG ...
float dx
Definition svg_fragment.hpp:36
bool is_identity() const
True when this is the do-nothing transform (no attribute is emitted).
float pivot_x
Definition svg_fragment.hpp:39
float rotate_deg
rotation about (pivot_x, pivot_y)
Definition svg_fragment.hpp:37
float pivot_y
Definition svg_fragment.hpp:39
float scale
uniform scale about (pivot_x, pivot_y)
Definition svg_fragment.hpp:38
float dy
translate, SVG coords
Definition svg_fragment.hpp:36