Skip to content

Commit b5ff4ab

Browse files
committed
fix curve formula window
1 parent 40cfae4 commit b5ff4ab

1 file changed

Lines changed: 86 additions & 4 deletions

File tree

src/app/ui/formula_window.rs

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
33
use 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+
512
pub(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

Comments
 (0)