viewer Sprint 5 완성 — 한글 폰트 + 슬라이더 자동 재생성
- Windows Malgun Gothic 폰트 로드 (한글 지원) - param_slider! 매크로: drag_released() / lost_focus() 시 자동 rebuild_mesh() - "▶ 적용 (Apply)" 버튼은 manual fallback으로 유지 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -278,6 +278,27 @@ impl RenderState {
|
||||
|
||||
// ── egui ──────────────────────────────────────────────────────────────
|
||||
let egui_ctx = egui::Context::default();
|
||||
|
||||
// Load Korean system font (Windows Malgun Gothic) for CJK support
|
||||
{
|
||||
let mut fonts = egui::FontDefinitions::default();
|
||||
let font_path = "C:\\Windows\\Fonts\\malgun.ttf";
|
||||
if let Ok(data) = std::fs::read(font_path) {
|
||||
fonts.font_data.insert(
|
||||
"MalgunGothic".to_owned(),
|
||||
egui::FontData::from_owned(data),
|
||||
);
|
||||
// Insert as primary font (index 0) so Korean renders by default
|
||||
for family in fonts.families.values_mut() {
|
||||
family.insert(0, "MalgunGothic".to_owned());
|
||||
}
|
||||
egui_ctx.set_fonts(fonts);
|
||||
log::info!("Korean font loaded: {}", font_path);
|
||||
} else {
|
||||
log::warn!("Korean font not found at {}; UI labels will show boxes", font_path);
|
||||
}
|
||||
}
|
||||
|
||||
let egui_state = egui_winit::State::new(
|
||||
egui_ctx.clone(),
|
||||
egui::ViewportId::ROOT,
|
||||
@@ -408,35 +429,28 @@ impl RenderState {
|
||||
ui.heading("교량 속성");
|
||||
ui.separator();
|
||||
|
||||
let prev = p.span_m;
|
||||
ui.label("경간 (m)");
|
||||
ui.add(egui::Slider::new(&mut p.span_m, 20.0..=80.0).step_by(1.0));
|
||||
if (p.span_m - prev).abs() > 0.001 { dirty = true; }
|
||||
// Helper: slider that auto-applies on drag release
|
||||
macro_rules! param_slider {
|
||||
($label:expr, $val:expr, $range:expr, $step:expr) => {{
|
||||
ui.label($label);
|
||||
let r = ui.add(egui::Slider::new($val, $range).step_by($step));
|
||||
if r.drag_released() || r.lost_focus() { apply = true; dirty = true; }
|
||||
if r.changed() { dirty = true; }
|
||||
}};
|
||||
}
|
||||
|
||||
let prev = p.girder_count;
|
||||
ui.label("거더 수");
|
||||
ui.add(egui::Slider::new(&mut p.girder_count, 3..=7));
|
||||
if p.girder_count != prev { dirty = true; }
|
||||
|
||||
let prev = p.girder_spacing;
|
||||
ui.label("c/c 간격 (mm)");
|
||||
ui.add(egui::Slider::new(&mut p.girder_spacing, 1_500.0..=4_000.0).step_by(100.0));
|
||||
if (p.girder_spacing - prev).abs() > 1.0 { dirty = true; }
|
||||
|
||||
let prev = p.girder_height;
|
||||
ui.label("거더 높이 (mm)");
|
||||
ui.add(egui::Slider::new(&mut p.girder_height, 1_000.0..=3_000.0).step_by(100.0));
|
||||
if (p.girder_height - prev).abs() > 1.0 { dirty = true; }
|
||||
|
||||
let prev = p.slab_thickness;
|
||||
ui.label("슬래브 두께 (mm)");
|
||||
ui.add(egui::Slider::new(&mut p.slab_thickness, 150.0..=400.0).step_by(10.0));
|
||||
if (p.slab_thickness - prev).abs() > 1.0 { dirty = true; }
|
||||
param_slider!("경간 (m)", &mut p.span_m, 20.0..=80.0, 1.0);
|
||||
param_slider!("거더 수", &mut p.girder_count, 3..=7, 1.0);
|
||||
param_slider!("c/c 간격 (mm)", &mut p.girder_spacing, 1_500.0..=4_000.0, 100.0);
|
||||
param_slider!("거더 높이 (mm)",&mut p.girder_height, 1_000.0..=3_000.0, 100.0);
|
||||
param_slider!("슬래브 두께(mm)",&mut p.slab_thickness, 150.0..=400.0, 10.0);
|
||||
|
||||
ui.separator();
|
||||
if dirty {
|
||||
apply = ui.button("▶ 적용").clicked();
|
||||
} else {
|
||||
if dirty && !apply {
|
||||
// Manual apply button as fallback
|
||||
if ui.button("▶ 적용 (Apply)").clicked() { apply = true; }
|
||||
ui.small("* 슬라이더를 놓으면 자동 적용");
|
||||
} else if !dirty {
|
||||
ui.label("✓ 최신 상태");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user