1 /**
2  * A read-only static text label.
3  *
4  * `Label` wraps the Win32 `"STATIC"` control class with `SS_LEFT` styling. It
5  * displays text and is not interactive (it carries no `WS_TABSTOP`), so it is
6  * skipped in the keyboard tab order. Its preferred size is computed from the
7  * measured extent of its text in the control's own font.
8  */
9 module deft.controls.label;
10 
11 version (Windows):
12 
13 import core.sys.windows.windows;
14 
15 import deft.controls.control;
16 import deft.util.strings;
17 import deft.widget;
18 
19 /// A non-interactive label that displays a single run of static text.
20 class Label : Control
21 {
22 	private string text_;
23 
24 	/// Create a label showing `text` inside `parent`.
25 	this(Widget parent, string text)
26 	{
27 		super(parent, "STATIC", SS_LEFT);
28 		setText(text);
29 	}
30 
31 	/// Set the label's text, remembering it for size measurement.
32 	override void setText(string text)
33 	{
34 		text_ = text;
35 		super.setText(text);
36 	}
37 
38 	/**
39 	 * Compute the preferred size from the text extent.
40 	 *
41 	 * The control's current font is selected into its device context and the
42 	 * UTF-16 form of the stored text is measured with `GetTextExtentPoint32W`.
43 	 * A small height floor keeps short or empty labels from collapsing.
44 	 */
45 	override Size getPreferredSize()
46 	{
47 		if (handle is null || text_.length == 0)
48 			return Size(0, 20);
49 
50 		const(wchar)* wtext = text_.toWStringz;
51 		int len = 0;
52 		while (wtext[len] != '\0')
53 			++len;
54 
55 		HDC hdc = GetDC(handle);
56 		if (hdc is null)
57 			return Size(0, 20);
58 
59 		HFONT font = cast(HFONT) SendMessageW(handle, WM_GETFONT, 0, 0);
60 		HGDIOBJ oldFont = font !is null ? SelectObject(hdc, font) : null;
61 
62 		SIZE sz;
63 		GetTextExtentPoint32W(hdc, wtext, len, &sz);
64 
65 		if (font !is null)
66 			SelectObject(hdc, oldFont);
67 		ReleaseDC(handle, hdc);
68 
69 		int height = sz.cy < 20 ? 20 : sz.cy;
70 		return Size(sz.cx, height);
71 	}
72 }