1 /*
2 Copyright (c) 2013 Andrey Penechko
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license the "Software" to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 module anchovy.gui.textline;
30 
31 import anchovy.gui;
32 public import anchovy.graphics.texrectarray;
33 import anchovy.graphics.interfaces.irenderer;
34 import anchovy.graphics.font.fontmanager;
35 
36 class TextLine
37 {
38 
39 public:
40 
41 	this()
42 	{
43 		_text = "";
44 	}
45 
46 	void font(Font newFont) @property
47 	{
48 		if (newFont is null) return;
49 		_font = newFont;
50 		if (!_isInited || newFont != _font)
51 			init();
52 	}
53 
54 	Font font() @property
55 	{
56 		return _font;
57 	}
58 
59 	bool isInited() @property
60 	{
61 		return _isInited;
62 	}
63 	
64 	void update()
65 	{
66 		if (text.length == 0 || !_isInited) return;
67 		if (_isDirty)
68 		{
69 			_geometry.load;
70 			_isDirty = false;
71 		}
72 	}
73 
74 	uint width() @property
75 	{
76 		return _width;
77 	}
78 
79 	uint height() @property
80 	{
81 		return _height;
82 	}
83 
84 	ivec2 size() @property
85 	{
86 		return ivec2(_width, _height);
87 	}
88 
89 	TexRectArray geometry() @property
90 	{
91 		return _geometry;
92 	}
93 
94 	dstring text() @property
95 	{
96 		return _text;
97 	}
98 
99 	dstring text(in string newText) @property
100 	{
101 		return text = to!dstring(newText);
102 	}
103 
104 	dstring text(in dstring newText) @property
105 	{
106 		if (_text == newText)
107 		{
108 			return _text;
109 		}
110 
111 		_text = newText;
112 		if (!_isInited) return _text;
113 
114 		_geometry.vertieces = null;
115 		_cursorX = 0;
116 		
117 		appendGlyphs(_text, _font);
118 		_isDirty = true;
119 
120 		return _text;
121 	}
122 
123 	string fontName() @property
124 	{
125 		return _fontName;
126 	}
127 
128 	void fontName(string newFontName) @property
129 	{
130 		_fontName = newFontName;
131 	}
132 
133 	///Supports chaining
134 	TextLine append(in string text)
135 	{
136 		return append(to!dstring(text));
137 	}
138 
139 	TextLine append(in dstring text)
140 	{
141 		appendGlyphs(_text, _font);
142 		_isDirty = true;
143 		return this;
144 	}
145 
146 protected:
147 
148 	void init()
149 	{
150 		_geometry = new TexRectArray;
151 		_height = _font.size;
152 		appendGlyphs(_text, _font);
153 		_isInited = true;
154 	}
155 
156 	void appendGlyphs(in dstring text, Font font)
157 	{
158 		foreach(dchar chr; text)
159 		{
160 			Glyph* glyph = font.getGlyph(chr);
161 			if (glyph !is null && chr == '\t')
162 			{
163 				_cursorX += glyph.metrics.advanceX * _tabSize;
164 				continue;
165 			}
166 			if (glyph is null) glyph = font.getGlyph('?');
167 			
168 			int x  =  glyph.metrics.offsetX + _cursorX;
169 			int y  =  font.verticalOffset - glyph.metrics.offsetY;
170 			int w  =  glyph.metrics.width;
171 			int h  =  glyph.metrics.height;
172 			int tx =  glyph.atlasPosition.x;
173 			int ty =  glyph.atlasPosition.y;
174 			
175 			//whitespace
176 			if (w == 0 || h == 0)
177 			{
178 				_cursorX += glyph.metrics.advanceX;
179 				continue;
180 			}
181 
182 			_geometry.appendQuad(Rect(x, y, w, h), Rect(tx, ty, w, h));
183 			_cursorX += glyph.metrics.advanceX;
184 		}
185 
186 		_width = _cursorX;
187 	}
188 
189 protected:
190 	uint _width;
191 	uint _height;
192 	dstring _text;
193 	bool _isInited = false;
194 	
195 	TexRectArray _geometry;
196 	uint _cursorX;
197 	bool _isDirty = true;
198 	
199 	Font _font;
200 	string _fontName;
201 	
202 	ubyte _tabSize = 4;
203 }