ailloli_ui_editor/paint/
folding_painter.rs

1//! Collapsed-fold placeholder label shaping and positioning.
2
3use ailloli_ui_core::TextStyle;
4use ailloli_ui_text::{TextLayoutParams, TextSystem, WrapMode};
5
6use crate::code::FoldRegion;
7use crate::layout::EditorTextRun;
8use crate::paint::EditorPaintItem;
9use crate::{CodeTheme, EditorStyle};
10
11/// Builds a shaped summary label after a collapsed fold header.
12///
13/// The first collapsed region starting at `run.index` wins. The label reports
14/// [`FoldRegion::hidden_line_count`], is placed 12 logical pixels after the
15/// shaped run width, and uses the theme's line-number color. No match returns
16/// `None`.
17///
18/// # Examples
19///
20/// ```
21/// use ailloli_ui_core::{Color, FontId, TextStyle};
22/// use ailloli_ui_editor::{layout::EditorTextRun, paint::folding_painter::fold_placeholder_item_for_run, CodeTheme, EditorStyle, FoldRegion};
23/// use ailloli_ui_text::{TextLayoutParams, TextSystem};
24/// let mut system = TextSystem::new();
25/// let layout = system.layout_cached(TextLayoutParams::new("fn f() {", TextStyle::new(FontId::Mono, 13, Color::WHITE)));
26/// let run = EditorTextRun { index: 1, byte_range: 0..8, baseline_y: 12.0, layout };
27/// let item = fold_placeholder_item_for_run(0.0, 0.0, &run, &[FoldRegion::new(1, 3).collapsed(true)], EditorStyle::default(), CodeTheme::default(), &mut system);
28/// assert!(item.is_some());
29/// ```
30pub fn fold_placeholder_item_for_run(
31    content_x: f32,
32    content_y: f32,
33    run: &EditorTextRun,
34    fold_regions: &[FoldRegion],
35    style: EditorStyle,
36    theme: CodeTheme,
37    text_system: &mut TextSystem,
38) -> Option<EditorPaintItem> {
39    let region = fold_regions
40        .iter()
41        .find(|region| region.collapsed && region.start_line == run.index)?;
42    let label = format!("  ... {} lines folded", region.hidden_line_count());
43    let layout = text_system.layout_cached(TextLayoutParams {
44        text: &label,
45        style: TextStyle::new(style.font, style.px_size, theme.line_number),
46        max_width: None,
47        wrap_mode: WrapMode::NoWrap,
48    });
49    Some(EditorPaintItem::FoldPlaceholder {
50        pos: [
51            content_x + run.layout.width() + 12.0,
52            content_y + run.baseline_y,
53        ],
54        color: theme.line_number,
55        layout,
56    })
57}