StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.
| 1 | //! Granular initialization system for StratoUI |
| 2 | //! |
| 3 | //! This module provides fine-grained control over the initialization process, |
| 4 | //! allowing developers to customize font loading, logging, and other aspects |
| 5 | //! of the framework initialization. |
| 6 | |
| 7 | use std::sync::{Arc, OnceLock, RwLock}; |
| 8 | use strato_core::{Result, StratoError}; |
| 9 | use strato_renderer::text::TextRenderer; |
| 10 | |
| 11 | /// Global text renderer instance to avoid multiple cosmic_text initializations |
| 12 | static GLOBAL_TEXT_RENDERER: OnceLock<Arc<RwLock<TextRenderer>>> = OnceLock::new(); |
| 13 | |
| 14 | /// Configuration for StratoUI initialization |
| 15 | #[derive(Debug, Clone)] |
| 16 | pub struct InitConfig { |
| 17 | /// Enable detailed logging during initialization |
| 18 | pub enable_logging: bool, |
| 19 | /// Skip problematic system fonts (like mstmc.ttf) |
| 20 | pub skip_problematic_fonts: bool, |
| 21 | /// Maximum number of font faces to load (None = unlimited) |
| 22 | pub max_font_faces: Option<usize>, |
| 23 | /// Custom font directories to search |
| 24 | pub custom_font_dirs: Vec<String>, |
| 25 | /// Preferred fonts to load first |
| 26 | pub preferred_fonts: Vec<String>, |
| 27 | } |
| 28 | |
| 29 | impl Default for InitConfig { |
| 30 | fn default() -> Self { |
| 31 | Self { |
| 32 | enable_logging: false, |
| 33 | skip_problematic_fonts: true, |
| 34 | max_font_faces: Some(50), |
| 35 | custom_font_dirs: Vec::new(), |
| 36 | preferred_fonts: vec![ |
| 37 | "Segoe UI".to_string(), |
| 38 | "Arial".to_string(), |
| 39 | "Helvetica".to_string(), |
| 40 | ], |
| 41 | } |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | /// Builder for step-by-step initialization |
| 46 | pub struct InitBuilder { |
| 47 | config: InitConfig, |
| 48 | core_initialized: bool, |
| 49 | widgets_initialized: bool, |
| 50 | platform_initialized: bool, |
| 51 | } |
| 52 | |
| 53 | impl InitBuilder { |
| 54 | /// Create a new initialization builder |
| 55 | pub fn new() -> Self { |
| 56 | Self { |
| 57 | config: InitConfig::default(), |
| 58 | core_initialized: false, |
| 59 | widgets_initialized: false, |
| 60 | platform_initialized: false, |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | /// Set custom configuration |
| 65 | pub fn with_config(mut self, config: InitConfig) -> Self { |
| 66 | self.config = config; |
| 67 | self |
| 68 | } |
| 69 | |
| 70 | /// Initialize only the core module |
| 71 | pub fn init_core(&mut self) -> Result<&mut Self> { |
| 72 | if self.core_initialized { |
| 73 | return Ok(self); |
| 74 | } |
| 75 | |
| 76 | // Initialize core first (which includes logging) |
| 77 | strato_core::init()?; |
| 78 | self.core_initialized = true; |
| 79 | |
| 80 | if self.config.enable_logging { |
| 81 | strato_core::strato_trace!(strato_core::logging::LogCategory::Core, "Core initialized"); |
| 82 | } |
| 83 | |
| 84 | Ok(self) |
| 85 | } |
| 86 | |
| 87 | /// Initialize only the widgets module |
| 88 | pub fn init_widgets(&mut self) -> Result<&mut Self> { |
| 89 | if !self.core_initialized { |
| 90 | self.init_core()?; |
| 91 | } |
| 92 | |
| 93 | if self.widgets_initialized { |
| 94 | return Ok(self); |
| 95 | } |
| 96 | |
| 97 | if self.config.enable_logging { |
| 98 | strato_core::strato_trace!( |
| 99 | strato_core::logging::LogCategory::Core, |
| 100 | "Initializing widgets..." |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | strato_widgets::init()?; |
| 105 | self.widgets_initialized = true; |
| 106 | |
| 107 | if self.config.enable_logging { |
| 108 | strato_core::strato_trace!( |
| 109 | strato_core::logging::LogCategory::Core, |
| 110 | "Widgets initialized" |
| 111 | ); |
| 112 | } |
| 113 | |
| 114 | Ok(self) |
| 115 | } |
| 116 | |
| 117 | /// Initialize only the platform module with optimized font loading |
| 118 | pub fn init_platform(&mut self) -> Result<&mut Self> { |
| 119 | if !self.core_initialized { |
| 120 | self.init_core()?; |
| 121 | } |
| 122 | |
| 123 | if self.platform_initialized { |
| 124 | return Ok(self); |
| 125 | } |
| 126 | |
| 127 | if self.config.enable_logging { |
| 128 | strato_core::strato_trace!( |
| 129 | strato_core::logging::LogCategory::Platform, |
| 130 | "Initializing platform with font optimizations..." |
| 131 | ); |
| 132 | } |
| 133 | |
| 134 | // Initialize platform with our custom configuration |
| 135 | crate::init().map_err(|e| { |
| 136 | strato_core::StratoError::platform(format!("Platform init failed: {}", e)) |
| 137 | })?; |
| 138 | |
| 139 | // Initialize the global text renderer with optimizations |
| 140 | self.init_optimized_text_renderer()?; |
| 141 | |
| 142 | self.platform_initialized = true; |
| 143 | |
| 144 | if self.config.enable_logging { |
| 145 | strato_core::strato_trace!( |
| 146 | strato_core::logging::LogCategory::Platform, |
| 147 | "Platform initialized" |
| 148 | ); |
| 149 | } |
| 150 | |
| 151 | Ok(self) |
| 152 | } |
| 153 | |
| 154 | /// Initialize all modules at once |
| 155 | pub fn init_all(&mut self) -> Result<()> { |
| 156 | self.init_core()?.init_widgets()?.init_platform()?; |
| 157 | Ok(()) |
| 158 | } |
| 159 | |
| 160 | /// Initialize the optimized text renderer |
| 161 | fn init_optimized_text_renderer(&self) -> Result<()> { |
| 162 | if GLOBAL_TEXT_RENDERER.get().is_some() { |
| 163 | return Ok(()); // Already initialized |
| 164 | } |
| 165 | |
| 166 | // Create optimized text renderer |
| 167 | strato_core::strato_trace!( |
| 168 | strato_core::logging::LogCategory::Platform, |
| 169 | "Creating optimized TextRenderer" |
| 170 | ); |
| 171 | let text_renderer = TextRenderer::new(); |
| 172 | |
| 173 | GLOBAL_TEXT_RENDERER |
| 174 | .set(Arc::new(RwLock::new(text_renderer))) |
| 175 | .map_err(|_| StratoError::platform("Failed to set global text renderer".to_string()))?; |
| 176 | |
| 177 | Ok(()) |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | impl Default for InitBuilder { |
| 182 | fn default() -> Self { |
| 183 | Self::new() |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | /// Get the global text renderer instance |
| 188 | pub fn get_text_renderer() -> Option<Arc<RwLock<TextRenderer>>> { |
| 189 | GLOBAL_TEXT_RENDERER.get().cloned() |
| 190 | } |
| 191 | |
| 192 | /// Convenience function for full initialization with default config |
| 193 | pub fn init_all() -> Result<()> { |
| 194 | InitBuilder::new().init_all() |
| 195 | } |
| 196 | |
| 197 | /// Convenience function for initialization with custom config |
| 198 | pub fn init_with_config(config: InitConfig) -> Result<()> { |
| 199 | InitBuilder::new().with_config(config).init_all() |
| 200 | } |
| 201 | |
| 202 | /// Check if the framework is fully initialized |
| 203 | pub fn is_initialized() -> bool { |
| 204 | GLOBAL_TEXT_RENDERER.get().is_some() |
| 205 | } |
| 206 | |
| 207 | #[cfg(test)] |
| 208 | mod tests { |
| 209 | use super::*; |
| 210 | |
| 211 | #[test] |
| 212 | fn test_init_config_default() { |
| 213 | let config = InitConfig::default(); |
| 214 | assert!(!config.enable_logging); |
| 215 | assert!(config.skip_problematic_fonts); |
| 216 | assert_eq!(config.max_font_faces, Some(50)); |
| 217 | } |
| 218 | |
| 219 | #[test] |
| 220 | fn test_init_builder() { |
| 221 | let mut builder = InitBuilder::new(); |
| 222 | assert!(!builder.core_initialized); |
| 223 | assert!(!builder.widgets_initialized); |
| 224 | assert!(!builder.platform_initialized); |
| 225 | } |
| 226 | } |
| 227 |