figcraft/plugins/examples/counter/src/lib.rs

60 lines
2.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Counter: a widget on the canvas with − and + buttons around a count. Each click calls the
//! plugin back with the widget's state; it hands back the new count and the redrawn widget.
use figcraft_plugin_sdk::{Input, Result, Value, entry, json, render_widget};
/// The count stays within ± this.
const LIMIT: i64 = 999_999;
/// The count after clicking `target` (none: the widget was just inserted).
fn next(count: i64, target: Option<&str>) -> i64 {
let n = match target {
Some("increment") => count.saturating_add(1),
Some("decrement") => count.saturating_sub(1),
_ => count,
};
n.clamp(-LIMIT, LIMIT)
}
/// A square button that calls back with `target`.
fn button(target: &str, name: &str, label: &str) -> Value {
json!({"type": "frame", "name": name, "target": target, "layout": "horizontal", "justify": "center", "width": 32, "height": 32, "radius": 8, "fill": "#F0F0F0",
"children": [{"type": "text", "text": label, "size": 16, "bold": true, "color": "#1E1E1E"}]})
}
/// The widget showing `count`.
fn view(count: i64) -> Value {
json!({"type": "frame", "name": "Counter", "layout": "horizontal", "gap": 12, "padding": 12, "radius": 12,
"fill": "#FFFFFF", "stroke": "#D9D9D9", "children": [
button("decrement", "Decrease", "−"),
{"type": "text", "name": "Count", "text": count.to_string(), "size": 24, "bold": true, "color": "#1E1E1E"},
button("increment", "Increase", "+"),
]})
}
fn run(input: Input) -> Result<Value> {
let w = input.widget.ok_or("Insert the counter from Plugins ▸ Widgets")?;
let count = next(w.state.get("count").and_then(Value::as_i64).unwrap_or(0), w.target.as_deref());
render_widget(&json!({"state": {"count": count}, "root": view(count)}))?;
Ok(json!({"count": count}))
}
entry!(run);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_within_its_limit() {
assert_eq!(next(0, None), 0);
assert_eq!(next(4, Some("increment")), 5);
assert_eq!(next(4, Some("decrement")), 3);
assert_eq!(next(LIMIT, Some("increment")), LIMIT);
assert_eq!(next(i64::MIN, Some("decrement")), -LIMIT);
assert_eq!(next(2, Some("other")), 2);
assert_eq!(view(3)["children"][1]["text"], "3");
assert!(run(Input::default()).is_err(), "it only runs as a widget");
}
}