Usability & Ergonomics Improvements
All issues identified across Sections 3.1, 3.2, and 3.3 have been
resolved, verified with unit tests, automated compilation checks under
`-D float_literal_f32_fallback`, and headless SVG export runs.
-
**[angle.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/angle.rs)**:
- Implemented `From<f64>` and `From<usize>` for `Degrees`.
- Added unit tests `from_integer` and `from_f64` to verify conversion
accuracy.
-
**[fontsize.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/fontsize.rs)**:
- Implemented `From<f64>` for `FontSize`.
- Refactored `FontSize::value(self)` to pass Copy type by value.
- Added unit test `font_size_conversions`.
-
**[general.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general.rs)**:
- Implemented `From<f64>`, `From<i32>`, and `From<usize>` for
`AnimationSpeed`.
- Added unit test `animation_speed_conversions`.
- Re-exported `macroquad` crate (`pub use macroquad;`) so downstream
code and macro expansions have reliable direct access.
-
**[export.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)**:
- Made `parse_svg_export_arg()` public.
- Implemented `run_headless_svg_export<F>(mut build_commands: F,
filename: &str) -> Result<(), ExportError>` that executes commands
using `app.step_animations()`, avoiding all window/GUI dependencies
and never calling `std::process::exit`.
- Updated `handle_svg_export` to delegate to
`run_headless_svg_export`.
-
**[lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs)**:
- Extracted `pub fn step_animations(&mut self)` from `update(&mut
self)`, allowing command queue draining and tween stepping
headlessly without querying window mouse position or events.
-
**[state.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/state.rs)**:
- Changed `TurtleWorld::new()` to initialize camera with
`Camera2D::default()` instead of querying `screen_width()` /
`screen_height()`, eliminating panics when running without a
Macroquad window.
-
**[turtle-lib-macros/src/lib.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib-macros/src/lib.rs)**:
- Added `validate_input` helper providing clean compile diagnostics
with spans for:
- Multiple arguments: `#[turtle_main] functions must take either 0
arguments or a single &mut TurtlePlan`
- Non-unit return types: `#[turtle_main] functions cannot have a
return type`
- Async functions: `#[turtle_main] functions cannot be async`
- Replaced `#[macroquad::main]` wrapper expansion with a native `fn
main()` that inspects CLI arguments first. If `--export-svg` is
present, it runs `run_headless_svg_export` directly and returns
cleanly without opening a window. Otherwise, it launches
`macroquad::Window::new(#window_title, async { ... })`.
- Added 5 unit tests in `turtle-lib-macros` testing signature
validation.
-
**[.vscode/launch.json](file:///home/dietrich/Projekte/Source/turtlers/.vscode/launch.json)**:
- Removed stale references to nonexistent `turtle-example` and
`turtle-ui`.
- Added debug configurations for `turtle-lib` tests,
`turtle-lib-macros` tests, `hello_turtle`, and `breadboard`.
-
**[breadboard.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/breadboard.rs)**:
- Refactored example to use `#[turtle_main("Breadboard")]`.
- Removed `#[cfg(feature = "svg")]` and the early-exit message; the
example now renders directly on screen by default and supports
`--features svg -- --export-svg breadboard.svg`.
-
**[README.md](file:///home/dietrich/Projekte/Source/turtlers/README.md)**:
- Documented optional user-level `~/.cargo/config.toml` mold/lld
fast-linking configuration under "Building and Running".
---
```bash
cargo test --workspace
```
- **Result**: 21 passed (16 in `turtle-lib`, 5 in `turtle-lib-macros`),
34 doctests passed, 0 failed.
```bash
RUSTFLAGS="-D float_literal_f32_fallback" cargo check --workspace
--all-targets --all-features
RUSTFLAGS="-D float_literal_f32_fallback" cargo check --package
turtle-lib --examples --all-features
```
- **Result**: Passed with 0 errors and 0 fallback warnings across all
workspace crates and all 30 examples.
```bash
cargo run --package turtle-lib --example hello_turtle --features svg --
--export-svg hello.svg
cargo run --package turtle-lib --example breadboard --features svg --
--export-svg breadboard.svg
```
- **Result**: Both exported SVG files successfully and exited with code
0 without creating or flashing a graphical window.
```bash
cargo check --package turtle-lib --example breadboard
```
- **Result**: Compiled cleanly with 0 errors when SVG feature is
disabled.
This commit is contained in:
@@ -1,48 +1,11 @@
|
||||
//! Breadboard circuit diagram example.
|
||||
//!
|
||||
//! Demonstrates structured procedural drawing of an electronics solderless breadboard.
|
||||
//! Run normally to display on screen, or export to SVG with:
|
||||
//! `cargo run --package turtle-lib --example breadboard --features svg -- --export-svg breadboard.svg`
|
||||
|
||||
use turtle_lib::*;
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
#[macroquad::main("Export SVG")]
|
||||
async fn main() {
|
||||
// Create turtle plan
|
||||
let mut turtle = create_turtle_plan();
|
||||
|
||||
// Set instant mode so commands execute immediately
|
||||
turtle.set_speed(1200).set_pen_width(0.5);
|
||||
|
||||
breadboard(&mut turtle, 65);
|
||||
|
||||
turtle.hide();
|
||||
let mut app = TurtleApp::new().with_commands(turtle.build());
|
||||
use macroquad::{
|
||||
input::{is_key_pressed, KeyCode},
|
||||
text::draw_text,
|
||||
window::{clear_background, next_frame},
|
||||
};
|
||||
|
||||
loop {
|
||||
clear_background(WHITE);
|
||||
app.update();
|
||||
app.render();
|
||||
|
||||
draw_text("Press E for SVG export", 20.0, 40.0, 32.0, BLACK);
|
||||
|
||||
if is_key_pressed(KeyCode::E) {
|
||||
match app.export_drawing("test.svg", export::DrawingFormat::Svg) {
|
||||
Ok(_) => println!("SVG exported to test.svg"),
|
||||
Err(e) => eprintln!("Export error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
next_frame().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "svg"))]
|
||||
fn main() {
|
||||
println!("SVG export is not enabled. Build with --features svg");
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin(t: &mut TurtlePlan, size: f32) {
|
||||
t.left(90.0).forward(size / 2.0);
|
||||
for _ in 0..5 {
|
||||
@@ -51,7 +14,6 @@ fn pin(t: &mut TurtlePlan, size: f32) {
|
||||
t.right(90.0).forward(size / 2.0).left(90.0);
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_row(t: &mut TurtlePlan, count: usize) {
|
||||
for x in 0..count {
|
||||
pin(t, 5.0);
|
||||
@@ -61,7 +23,6 @@ fn pin_row(t: &mut TurtlePlan, count: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_column(t: &mut TurtlePlan, count: usize, x_coord: f32) {
|
||||
for x in 0..count {
|
||||
t.pen_up().go_to(vec2(x_coord, x as f32 * 10.0)).pen_down();
|
||||
@@ -69,7 +30,6 @@ fn pin_column(t: &mut TurtlePlan, count: usize, x_coord: f32) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_side(t: &mut TurtlePlan, count: usize, x_coord: f32, color: Color) {
|
||||
t.pen_up()
|
||||
.go_to(vec2(x_coord, -2.5))
|
||||
@@ -84,8 +44,7 @@ fn pin_side(t: &mut TurtlePlan, count: usize, x_coord: f32, color: Color) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn breadboard(t: &mut TurtlePlan, row_count: usize) {
|
||||
fn draw_breadboard(t: &mut TurtlePlan, row_count: usize) {
|
||||
pin_column(t, row_count, 0.0);
|
||||
pin_column(t, row_count, 65.0);
|
||||
pin_side(t, row_count, -15.0, BLUE);
|
||||
@@ -105,3 +64,10 @@ fn breadboard(t: &mut TurtlePlan, row_count: usize) {
|
||||
.forward(170.0)
|
||||
.right(90.0);
|
||||
}
|
||||
|
||||
#[turtle_main("Breadboard")]
|
||||
fn main(turtle: &mut TurtlePlan) {
|
||||
turtle.set_speed(1200).set_pen_width(0.5);
|
||||
draw_breadboard(turtle, 65);
|
||||
turtle.hide();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user