1 module prova.graphics.text.text;
2 
3 import prova.core,
4        prova.graphics,
5        prova.math;
6 
7 ///
8 enum TextAlign { LEFT, CENTER, RIGHT }
9 ///
10 enum TextBaseline { TOP, MIDDLE, BOTTOM, HANGING, ALPHABETIC }
11 
12 ///
13 class Text : Entity
14 {
15   ///
16   Color color;
17   ///
18   TextAlign textAlign;
19   ///
20   TextBaseline textBaseline;
21   private Sprite[] sprites;
22   private Glyph[] glyphs;
23   private Font font;
24   private string _text;
25 
26   ///
27   this(string text, Font font)
28   {
29     this.font = font;
30     this.text = text;
31   }
32 
33   ///
34   @property string text()
35   {
36     return _text;
37   }
38 
39   ///
40   @property void text(string text)
41   {
42     sprites.length = text.length;
43     glyphs.length = text.length;
44 
45     foreach(i; 0 .. text.length)
46     {
47       const int c = text[i];
48 
49       if(!font.hasGlyph(c))
50         continue;
51 
52       const Glyph glyph = font.getGlyph(c);
53 
54       Sprite sprite = new Sprite();
55       sprite.texture = font.texture;
56       sprite.clip = glyph.clip;
57       sprite.origin = Vector2(-glyph.clip.width / 2, glyph.clip.height / 2);
58 
59       sprites[i] = sprite;
60       glyphs[i] = glyph;
61     }
62 
63     _text = text;
64   }
65 
66   ///
67   Vector2 getSize()
68   {
69     Vector2 size = font.measureString(_text);
70 
71     return Vector2(size.x * scale.x, size.y * scale.y);
72   }
73 
74   ///
75   Rect getBounds()
76   {
77     Vector3 start = position + getOffset();
78     Vector2 size = getSize();
79 
80     return Rect(start.x, start.y, size.x, size.y);
81   }
82 
83   ///
84   override void draw(RenderTarget renderTarget, Matrix transform)
85   {
86     transform = transform.translate(getOffset());
87 
88     foreach(i; 0 .. _text.length)
89     {
90       Glyph glyph = glyphs[i];
91       Sprite sprite = sprites[i];
92 
93       sprite.tint = color;
94 
95       Vector2 offset = glyph.offset;
96 
97       if(i > 0)
98         offset += font.getKerning(_text[i - 1], _text[i]);
99 
100       renderTarget.drawSprite(sprite, transform.translate(offset));
101 
102       transform = transform.translate(glyph.advance);
103     }
104   }
105 
106   private Vector2 getOffset()
107   {
108     const Vector2 size = getSize();
109     Vector2 offset;
110 
111     if(textAlign == TextAlign.CENTER)
112       offset.x -= size.x / 2;
113     else if(textAlign == TextAlign.RIGHT)
114       offset.x -= size.x;
115 
116     final switch(textBaseline)
117     {
118       case TextBaseline.TOP:
119         break;
120       case TextBaseline.MIDDLE:
121         offset.y += (font.ascentLine - font.descentLine) * scale.y / 2;
122         break;
123       case TextBaseline.BOTTOM:
124         offset.y += (font.size - font.descentLine) * scale.y;
125         break;
126       case TextBaseline.HANGING:
127         offset.y += (font.ascentLine - font.size) * scale.y;
128         break;
129       case TextBaseline.ALPHABETIC:
130         offset.y += font.size * scale.y;
131         break;
132     }
133 
134     return offset;
135   }
136 }