ltk/widget/text_edit/
metrics.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::render::Canvas;
use crate::types::{ Length, Rect };

use super::theme;

/// Single-line geometry follows the field height, which is already physical.
pub( crate ) fn single_line_scale( rect: Rect ) -> f32
{
	rect.height / theme::HEIGHT
}

pub( crate ) fn single_line_pad_h( rect: Rect, pad_h: Option<f32> ) -> f32
{
	pad_h.unwrap_or_else( || theme::PAD_H * single_line_scale( rect ) )
}

/// Resolved layout of a multiline field, shared by sizing, drawing,
/// hit-testing and caret navigation so they all agree. `font_size` is in
/// font space (pre-`dpi_scale`); every other field is physical px.
#[ derive( Clone, Copy, Debug ) ]
pub( crate ) struct MultilineMetrics
{
	pub font_size: f32,
	pub glyph_h:   f32,
	pub line_h:    f32,
	pub pad_h:     f32,
	pub pad_v:     f32,
	pub caret_w:   f32,
	pub caret_h:   f32,
}

impl MultilineMetrics
{
	pub( crate ) fn resolve( canvas: &Canvas, font_size: Option<Length> ) -> Self
	{
		let font_size = super::resolve_font_size( canvas, font_size );
		let dpi       = canvas.dpi_scale().max( 1.0 );
		let glyph_h   = font_size * dpi;
		Self
		{
			font_size,
			glyph_h,
			line_h:  glyph_h * theme::LINE_H_MULT,
			pad_h:   canvas.geom_px( theme::PAD_H ),
			pad_v:   canvas.geom_px( theme::PAD_V_MULTI ),
			caret_w: ( theme::CARET_W * dpi ).round(),
			caret_h: glyph_h + theme::CARET_OVERHANG * dpi,
		}
	}

	pub( crate ) fn height_for_rows( &self, rows: u32 ) -> f32
	{
		rows as f32 * self.line_h + self.pad_v * 2.0
	}

	pub( crate ) fn inner_width( &self, rect: Rect ) -> f32
	{
		( rect.width - self.pad_h * 2.0 ).max( self.glyph_h )
	}

	pub( crate ) fn visible_lines( &self, rect: Rect ) -> usize
	{
		let inner_h = ( rect.height - self.pad_v * 2.0 ).max( self.line_h );
		( inner_h / self.line_h ).floor().max( 1.0 ) as usize
	}
}