1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module atelier.ui.label;
7 
8 import std.algorithm.comparison : min;
9 import std..string, std.conv;
10 import bindbc.sdl, bindbc.sdl.ttf;
11 import atelier.core, atelier.common, atelier.render;
12 import atelier.ui.gui_element;
13 
14 /// A single line of text.
15 final class Label : GuiElement {
16     private {
17         dstring _text;
18         Font _font;
19         int _charSpacing, _charScale = 1;
20     }
21 
22     @property {
23         /// Text
24         string text() const {
25             return to!string(_text);
26         }
27         /// Ditto
28         string text(string text_) {
29             _text = to!dstring(text_);
30             reload();
31             return text_;
32         }
33 
34         /// Font
35         Font font() const {
36             return cast(Font) _font;
37         }
38         /// Ditto
39         Font font(Font font_) {
40             _font = font_;
41             reload();
42             return _font;
43         }
44 
45         /// Additionnal spacing between each character
46         int charSpacing() const {
47             return _charSpacing;
48         }
49         /// Ditto
50         int charSpacing(int charSpacing_) {
51             return _charSpacing = charSpacing_;
52         }
53 
54         /// Characters scaling
55         int charScale() const {
56             return _charScale;
57         }
58         /// Ditto
59         int charScale(int charScale_) {
60             return _charScale = charScale_;
61         }
62     }
63 
64     /// Build label
65     this(string text_ = "", Font font = getDefaultFont()) {
66         setInitFlags(Init.notInteractable);
67         _font = font;
68         _text = to!dstring(text_);
69         reload();
70     }
71 
72     private void reload() {
73         Vec2f totalSize_ = Vec2f(0f, _font.ascent - _font.descent) * _charScale;
74         float lineWidth = 0f;
75         dchar prevChar;
76         foreach (dchar ch; _text) {
77             if (ch == '\n') {
78                 lineWidth = 0f;
79                 totalSize_.y += _font.lineSkip * _charScale;
80             }
81             else {
82                 const Glyph metrics = _font.getMetrics(ch);
83                 lineWidth += _font.getKerning(prevChar, ch) * _charScale;
84                 lineWidth += metrics.advance * _charScale;
85                 if (lineWidth > totalSize_.x)
86                     totalSize_.x = lineWidth;
87                 prevChar = ch;
88             }
89         }
90         size = totalSize_;
91     }
92 
93     override void draw() {
94         Vec2f pos = origin;
95         dchar prevChar;
96         foreach (dchar ch; _text) {
97             if (ch == '\n') {
98                 pos.x = origin.x;
99                 pos.y += _font.lineSkip * _charScale;
100                 prevChar = 0;
101             }
102             else {
103                 Glyph metrics = _font.getMetrics(ch);
104                 pos.x += _font.getKerning(prevChar, ch) * _charScale;
105                 Vec2f drawPos = Vec2f(pos.x + metrics.offsetX * _charScale,
106                         pos.y - metrics.offsetY * _charScale);
107                 metrics.draw(drawPos, _charScale, color, alpha);
108                 pos.x += (metrics.advance + _charSpacing) * _charScale;
109                 prevChar = ch;
110             }
111         }
112     }
113 }