aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRubén Beltrán del Río <jj@r.bdr.sh>2026-01-16 11:37:51 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-01-16 11:49:15 +0100
commit09c1181cb4df744f0ea34eb0f1fd325850f6b128 (patch)
treedc161e628a087754be29e5c514fc8290d49273e0
parentf53588e276fba9db2f3bee6a3421f60d7c458813 (diff)
Add support for custom stage typesHEADmain
-rw-r--r--CHANGELOG10
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--examples/generate_map.rs21
-rw-r--r--src/renderer.rs13
-rw-r--r--src/stage_type.rs27
-rw-r--r--tests/integration_test.rs14
7 files changed, 66 insertions, 23 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ba2e9bb..5ce93ec 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+## 1.1.0 - 2026-01-16
+
+### Changed
+
+* Stage type is now passed by reference.
+
+### Added
+
+* Allow for custom rendering.
+
## 1.0.0 - 2025-12-16
### Added
diff --git a/Cargo.lock b/Cargo.lock
index 0af0261..387deab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2011,7 +2011,7 @@ checksum = "c5a2c331c28b392f06cd9d81118a6f73b084708c6ff320457f4cbd75912d499b"
[[package]]
name = "wmap-renderer"
-version = "1.0.0"
+version = "1.1.0"
dependencies = [
"cairo-rs",
"criterion",
diff --git a/Cargo.toml b/Cargo.toml
index c19d1f2..08f0323 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "wmap-renderer"
-version = "1.0.0"
+version = "1.1.0"
edition = "2024"
license = "AGPL-3.0-or-later"
description = "A parser for wmap formatted Wardley Map files."
diff --git a/examples/generate_map.rs b/examples/generate_map.rs
index 2d83b0b..1728d52 100644
--- a/examples/generate_map.rs
+++ b/examples/generate_map.rs
@@ -9,27 +9,40 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Generate PNG with smart positioning
println!("Generating PNG with smart positioning...");
- let png_data = render_to_png(&map, StageType::Activities, &config)?;
+ let png_data = render_to_png(&map, &StageType::Activities, &config)?;
fs::write("example.png", png_data)?;
println!("Generated example.png");
// Generate SVG with smart positioning
println!("Generating SVG with smart positioning...");
- let svg_data = render_to_svg(&map, StageType::Activities, &config)?;
+ let svg_data = render_to_svg(&map, &StageType::Activities, &config)?;
fs::write("example.svg", svg_data)?;
println!("Generated example.svg");
// Generate with different stage type
println!("Generating with publication types stage type...");
- let png_publication_types = render_to_png(&map, StageType::PublicationTypes, &config)?;
+ let png_publication_types = render_to_png(&map, &StageType::PublicationTypes, &config)?;
fs::write("example_publication_types.png", png_publication_types)?;
println!("Generated example_publication_types.png");
+ // Generate with a custom stage type
+ println!("Generating with publication types stage type...");
+ let stage_type = StageType::Custom {
+ name: "My Stage Type".to_string(),
+ i: "Earlier".to_string(),
+ ii: "Early".to_string(),
+ iii: "Late".to_string(),
+ iv: "Later".to_string(),
+ };
+ let png_publication_types = render_to_svg(&map, &stage_type, &config)?;
+ fs::write("example_custom_stages.svg", png_publication_types)?;
+ println!("Generated example_publication_types.png");
+
// Generate without smart positioning (simple right-side positioning)
println!("Generating without smart positioning...");
let mut config_no_smart = Configuration::default();
config_no_smart.options.smart_label_positioning = false;
- let png_no_smart = render_to_png(&map, StageType::Activities, &config_no_smart)?;
+ let png_no_smart = render_to_png(&map, &StageType::Activities, &config_no_smart)?;
fs::write("example_no_smart_positioning.png", png_no_smart)?;
println!("Generated example_no_smart_positioning.png");
diff --git a/src/renderer.rs b/src/renderer.rs
index 69c3f70..d91c3f0 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -38,7 +38,7 @@ use crate::utils::percent_to_pixel;
/// Returns `RenderError` if the surface creation, rendering, or PNG encoding fails
pub fn render_to_png(
map: &Map,
- stage_type: StageType,
+ stage_type: &StageType,
configuration: &Configuration,
) -> Result<Vec<u8>, RenderError> {
// Safe cast: map dimensions are typically in the range of hundreds to thousands of pixels
@@ -80,7 +80,7 @@ pub fn render_to_png(
/// Returns `RenderError` if the surface creation or rendering fails
pub fn render_to_surface(
map: &Map,
- stage_type: StageType,
+ stage_type: &StageType,
configuration: &Configuration,
) -> Result<ImageSurface, RenderError> {
// Safe cast: map dimensions are typically in the range of hundreds to thousands of pixels
@@ -120,7 +120,7 @@ pub fn render_to_surface(
/// Returns `RenderError` if the surface creation, rendering, or file I/O fails
pub fn render_to_svg(
map: &Map,
- stage_type: StageType,
+ stage_type: &StageType,
configuration: &Configuration,
) -> Result<String, RenderError> {
let total_width = configuration.theme.sizes.map_width + configuration.theme.sizes.padding * 2.0;
@@ -150,7 +150,7 @@ pub fn render_to_svg(
fn render(
context: &Context,
map: &Map,
- stage_type: StageType,
+ stage_type: &StageType,
configuration: &Configuration,
) -> Result<(), RenderError> {
// Apply padding transform
@@ -177,7 +177,7 @@ fn render(
draw_background(context, configuration)?;
if configuration.options.show_background {
- draw_stage_patterns(context, stage_type, map, configuration)?;
+ draw_stage_patterns(context, map, configuration)?;
}
draw_axes(context, stage_type, map, configuration)?;
@@ -205,7 +205,6 @@ fn draw_background(context: &Context, configuration: &Configuration) -> Result<(
fn draw_stage_patterns(
context: &Context,
- _stage_type: StageType,
map: &Map,
configuration: &Configuration,
) -> Result<(), RenderError> {
@@ -276,7 +275,7 @@ fn draw_stage_patterns(
fn draw_axes(
context: &Context,
- stage_type: StageType,
+ stage_type: &StageType,
map: &Map,
configuration: &Configuration,
) -> Result<(), RenderError> {
diff --git a/src/stage_type.rs b/src/stage_type.rs
index ae80166..46486e1 100644
--- a/src/stage_type.rs
+++ b/src/stage_type.rs
@@ -1,5 +1,5 @@
/// Stage type used to analyze different aspects of a Wardley map
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum StageType {
#[default]
Activities,
@@ -24,12 +24,19 @@ pub enum StageType {
Understanding,
UserPerception,
EvolutionStage,
+ Custom {
+ name: String,
+ i: String,
+ ii: String,
+ iii: String,
+ iv: String,
+ },
}
impl StageType {
/// Returns the name of this stage type
#[must_use]
- pub fn name(&self) -> &'static str {
+ pub fn name(&self) -> &str {
match self {
Self::Activities => "Activities",
Self::Behavior => "Behavior",
@@ -53,6 +60,13 @@ impl StageType {
Self::Understanding => "Understanding",
Self::UserPerception => "User Perception",
Self::EvolutionStage => "Evolution Stage",
+ Self::Custom {
+ name,
+ i: _,
+ ii: _,
+ iii: _,
+ iv: _,
+ } => name,
}
}
@@ -61,7 +75,7 @@ impl StageType {
// Splitting it would reduce clarity and require additional complexity
#[allow(clippy::too_many_lines)]
#[must_use]
- pub fn stages(&self) -> [&'static str; 4] {
+ pub fn stages(&self) -> [&str; 4] {
match self {
Self::Activities => [
"Genesis",
@@ -170,6 +184,13 @@ impl StageType {
"Standard / expected / feeling of shock if not used",
],
Self::EvolutionStage => ["Stage I", "Stage II", "Stage III", "Stage IV"],
+ Self::Custom {
+ name: _,
+ i,
+ ii,
+ iii,
+ iv,
+ } => [i, ii, iii, iv],
}
}
}
diff --git a/tests/integration_test.rs b/tests/integration_test.rs
index 122ed5a..7ae228f 100644
--- a/tests/integration_test.rs
+++ b/tests/integration_test.rs
@@ -6,7 +6,7 @@ fn test_render_simple_map_to_png() {
let map = wmap_parser::parse(source);
let config = Configuration::default();
- let result = render_to_png(&map, StageType::default(), &config);
+ let result = render_to_png(&map, &StageType::default(), &config);
assert!(result.is_ok());
let png_data = result.unwrap();
@@ -22,7 +22,7 @@ fn test_render_simple_map_to_svg() {
let map = wmap_parser::parse(source);
let config = Configuration::default();
- let result = render_to_svg(&map, StageType::default(), &config);
+ let result = render_to_svg(&map, &StageType::default(), &config);
assert!(result.is_ok());
let svg_data = result.unwrap();
@@ -36,7 +36,7 @@ fn test_render_with_all_shapes() {
let map = wmap_parser::parse(source);
let config = Configuration::default();
- let result = render_to_png(&map, StageType::default(), &config);
+ let result = render_to_png(&map, &StageType::default(), &config);
assert!(result.is_ok());
}
@@ -47,9 +47,9 @@ fn test_render_with_different_stage_types() {
let config = Configuration::default();
// Test a few different stage types
- assert!(render_to_png(&map, StageType::Activities, &config).is_ok());
- assert!(render_to_png(&map, StageType::Cynefin, &config).is_ok());
- assert!(render_to_png(&map, StageType::Practice, &config).is_ok());
+ assert!(render_to_png(&map, &StageType::Activities, &config).is_ok());
+ assert!(render_to_png(&map, &StageType::Cynefin, &config).is_ok());
+ assert!(render_to_png(&map, &StageType::Practice, &config).is_ok());
}
#[test]
@@ -58,6 +58,6 @@ fn test_render_empty_map() {
let map = wmap_parser::parse(source);
let config = Configuration::default();
- let result = render_to_png(&map, StageType::default(), &config);
+ let result = render_to_png(&map, &StageType::default(), &config);
assert!(result.is_ok());
}