/// Configuration options for rendering #[derive(Debug, Clone)] pub struct Options { pub show_background: bool, pub smart_label_positioning: bool, } impl Default for Options { fn default() -> Self { Self { show_background: true, smart_label_positioning: true, } } } /// Color configuration #[derive(Debug, Clone)] pub struct Colors { pub background: (f64, f64, f64), pub axis: (f64, f64, f64), pub vertex: (f64, f64, f64), pub label: (f64, f64, f64), pub stage_foreground: (f64, f64, f64), pub stage_background: (f64, f64, f64), pub inertia: (f64, f64, f64), pub evolution: (f64, f64, f64), pub groups: Vec<(f64, f64, f64)>, } impl Default for Colors { fn default() -> Self { Self { background: (1.0, 1.0, 1.0), axis: (0.058824, 0.149020, 0.121569), // Deep Slate Green vertex: (0.058824, 0.149020, 0.121569), label: (0.058824, 0.149020, 0.121569), stage_foreground: (0.854901, 0.901960, 0.890196), stage_background: (1.0, 1.0, 1.0), inertia: (0.980392, 0.168627, 0.0), evolution: (0.309804, 0.560784, 0.901961), groups: vec![ (0.227451, 0.356863, 0.627451), // Olympic Blue (0.768627, 0.270588, 0.211765), // Jasper Red (0.560784, 0.745098, 0.572549), // Light Porcelain Green (0.980392, 0.835294, 0.360784), // Naples Yellow (0.925490, 0.611765, 0.670588), // Hermosa Pink ], } } } /// Size configuration #[derive(Debug, Clone)] pub struct Sizes { pub map_width: f64, pub map_height: f64, pub padding: f64, pub bottom_padding: f64, pub line_width: f64, pub vertex_size: f64, pub arrowhead_size: f64, pub stage_height: f64, } impl Default for Sizes { fn default() -> Self { Self { map_width: 1300.0, map_height: 1000.0, padding: 42.0, bottom_padding: 120.0, line_width: 0.5, vertex_size: 25.0, arrowhead_size: 10.0, stage_height: 100.0, } } } /// Font configuration #[derive(Debug, Clone)] pub struct Fonts { pub face: String, pub axis_label: f64, pub vertex_label: f64, pub note: f64, } impl Default for Fonts { fn default() -> Self { Self { face: "sans-serif".to_string(), axis_label: 14.0, vertex_label: 12.0, note: 12.0, } } } /// Line height configuration #[derive(Debug, Clone)] pub struct LineHeights { pub vertex_label: f64, pub note: f64, } impl Default for LineHeights { fn default() -> Self { Self { vertex_label: 18.0, note: 18.0, } } } /// Opacity configuration #[derive(Debug, Clone)] pub struct Opacity { pub groups: f64, } impl Default for Opacity { fn default() -> Self { Self { groups: 0.1 } } } /// Theme configuration #[derive(Debug, Clone, Default)] pub struct Theme { pub colors: Colors, pub sizes: Sizes, pub fonts: Fonts, pub line_heights: LineHeights, pub opacity: Opacity, } /// Main configuration struct #[derive(Debug, Clone, Default)] pub struct Configuration { pub options: Options, pub theme: Theme, } #[cfg(test)] mod tests { use super::*; #[test] fn test_default_configuration() { let configuration = Configuration::default(); const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; // Test options assert!(configuration.options.show_background); assert!(configuration.options.smart_label_positioning); // Test colors assert_eq!(configuration.theme.colors.background, (1.0, 1.0, 1.0)); assert_eq!( configuration.theme.colors.axis, (0.058_824, 0.149_020, 0.121_569) ); assert_eq!( configuration.theme.colors.vertex, (0.058_824, 0.149_020, 0.121_569) ); assert_eq!( configuration.theme.colors.label, (0.058_824, 0.149_020, 0.121_569) ); assert_eq!( configuration.theme.colors.stage_foreground, (0.854_901, 0.901_960, 0.890_196) ); assert_eq!(configuration.theme.colors.stage_background, (1.0, 1.0, 1.0)); assert_eq!( configuration.theme.colors.inertia, (0.980_392, 0.168_627, 0.0) ); assert_eq!( configuration.theme.colors.evolution, (0.309_804, 0.560_784, 0.901_961) ); assert_eq!(configuration.theme.colors.groups.len(), 5); // Test sizes assert!( (configuration.theme.sizes.map_width - 1300.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.sizes.map_height - 1000.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!((configuration.theme.sizes.padding - 42.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM); assert!( (configuration.theme.sizes.bottom_padding - 120.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.sizes.line_width - 0.5).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.sizes.vertex_size - 25.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.sizes.arrowhead_size - 10.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.sizes.stage_height - 100.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); // Test fonts assert_eq!(configuration.theme.fonts.face, "sans-serif"); assert!( (configuration.theme.fonts.axis_label - 14.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.fonts.vertex_label - 12.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!((configuration.theme.fonts.note - 12.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM); // Test line heights assert!( (configuration.theme.line_heights.vertex_label - 18.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); assert!( (configuration.theme.line_heights.note - 18.0).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM ); // Test opacity assert!((configuration.theme.opacity.groups - 0.1).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM); } }