22
33use super :: * ;
44
5+ const FORMULA_WINDOW_DEFAULT_HEIGHT : f32 = 520.0 ;
6+ const FORMULA_WINDOW_MIN_WIDTH : f32 = 450.0 ;
7+ const FORMULA_WINDOW_MIN_HEIGHT : f32 = 320.0 ;
8+ const FORMULA_WINDOW_SCREEN_MARGIN : f32 = 24.0 ;
9+ const FORMULA_WINDOW_CONTENT_MARGIN_X : f32 = 60.0 ;
10+ const FORMULA_WINDOW_FALLBACK_CHAR_WIDTH : f32 = 8.0 ;
11+
512pub ( super ) fn ui_formula_window ( app : & mut CurveFitApp , ctx : & egui:: Context ) {
613 if !app. panel . show_formula_window {
714 return ;
@@ -21,12 +28,15 @@ pub(super) fn ui_formula_window(app: &mut CurveFitApp, ctx: &egui::Context) {
2128 app. optimization_loss_metric ,
2229 ) ;
2330 let mut is_open = app. panel . show_formula_window ;
31+ let dark_mode = ctx. global_style ( ) . visuals . dark_mode ;
32+ let window_width = formula_window_width ( app, ctx, & formula_info, dark_mode) ;
2433 egui:: Window :: new ( tr ( language, "Model Formula" , "Формула модели" ) )
2534 . open ( & mut is_open)
26- . default_size ( egui:: vec2 ( 860.0 , 520.0 ) )
27- . min_width ( 560.0 )
28- . min_height ( 320.0 )
29- . resizable ( true )
35+ . default_size ( egui:: vec2 ( window_width, FORMULA_WINDOW_DEFAULT_HEIGHT ) )
36+ . min_width ( window_width)
37+ . max_width ( window_width)
38+ . min_height ( FORMULA_WINDOW_MIN_HEIGHT )
39+ . resizable ( [ false , true ] )
3040 . show ( ctx, |ui| {
3141 let formula_window_hint = tr (
3242 language,
@@ -94,3 +104,75 @@ pub(super) fn ui_formula_window(app: &mut CurveFitApp, ctx: &egui::Context) {
94104 } ) ;
95105 app. panel . show_formula_window = is_open;
96106}
107+
108+ fn formula_window_width (
109+ app : & mut CurveFitApp ,
110+ ctx : & egui:: Context ,
111+ formula_info : & ModelFormulaInfo ,
112+ dark_mode : bool ,
113+ ) -> f32 {
114+ let content_width = formula_info
115+ . sections
116+ . iter ( )
117+ . map ( |section| formula_section_width ( app, ctx, section, dark_mode) )
118+ . fold ( 0.0_f32 , f32:: max) ;
119+ let target_width = content_width + FORMULA_WINDOW_CONTENT_MARGIN_X ;
120+ let max_width = ( ctx. content_rect ( ) . width ( ) - 2.0 * FORMULA_WINDOW_SCREEN_MARGIN ) . max ( 320.0 ) ;
121+ let min_width = FORMULA_WINDOW_MIN_WIDTH . min ( max_width) ;
122+ target_width. clamp ( min_width, max_width)
123+ }
124+
125+ fn formula_section_width (
126+ app : & mut CurveFitApp ,
127+ ctx : & egui:: Context ,
128+ section : & FormulaReferenceSection ,
129+ dark_mode : bool ,
130+ ) -> f32 {
131+ let formula_width = app
132+ . cached_formula_svg ( & section. render_latex , dark_mode)
133+ . ok ( )
134+ . and_then ( |( _, bytes) | svg_width ( & bytes) )
135+ . unwrap_or_else ( || plain_text_width ( section. plain_text . as_str ( ) ) ) ;
136+
137+ let text_width = text_lines_width (
138+ ctx,
139+ egui:: TextStyle :: Small ,
140+ [ section. title . as_str ( ) , section. description . as_str ( ) ] . into_iter ( ) ,
141+ ) ;
142+
143+ formula_width. max ( text_width)
144+ }
145+
146+ fn text_lines_width < ' a > (
147+ ctx : & egui:: Context ,
148+ text_style : egui:: TextStyle ,
149+ texts : impl Iterator < Item = & ' a str > ,
150+ ) -> f32 {
151+ let font_id = text_style. resolve ( & ctx. global_style ( ) ) ;
152+ ctx. fonts_mut ( |fonts| {
153+ texts
154+ . flat_map ( str:: lines)
155+ . map ( str:: trim)
156+ . filter ( |line| !line. is_empty ( ) )
157+ . map ( |line| {
158+ fonts
159+ . layout_no_wrap ( line. to_owned ( ) , font_id. clone ( ) , egui:: Color32 :: WHITE )
160+ . size ( )
161+ . x
162+ } )
163+ . fold ( 0.0_f32 , f32:: max)
164+ } )
165+ }
166+
167+ fn plain_text_width ( text : & str ) -> f32 {
168+ text. lines ( )
169+ . map ( |line| line. chars ( ) . count ( ) as f32 * FORMULA_WINDOW_FALLBACK_CHAR_WIDTH )
170+ . fold ( 0.0_f32 , f32:: max)
171+ }
172+
173+ fn svg_width ( bytes : & [ u8 ] ) -> Option < f32 > {
174+ let svg = std:: str:: from_utf8 ( bytes) . ok ( ) ?;
175+ let after_attr = svg. split_once ( r#"width=""# ) ?. 1 ;
176+ let raw_width = after_attr. split_once ( '"' ) ?. 0 ;
177+ raw_width. parse ( ) . ok ( )
178+ }
0 commit comments