MyGUI 3.4.3
MyGUI_TextView.cpp
Go to the documentation of this file.
1/*
2 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3 * Distributed under the MIT License
4 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5 */
6
7#include "MyGUI_Precompiled.h"
8#include "MyGUI_TextView.h"
9
10namespace MyGUI
11{
12
13 namespace
14 {
15
16 template<typename T>
17 void setMin(T& _var, const T& _newValue)
18 {
19 if (_newValue < _var)
20 _var = _newValue;
21 }
22
23 template<typename T>
24 void setMax(T& _var, const T& _newValue)
25 {
26 if (_var < _newValue)
27 _var = _newValue;
28 }
29
30 }
31
32 class RollBackPoint
33 {
34 public:
35 void set(
36 size_t _position,
37 const UString::utf32string::const_iterator& _space_point,
38 size_t _count,
39 float _width)
40 {
41 position = _position;
42 space_point = _space_point;
43 count = _count;
44 width = _width;
45 rollback = true;
46 }
47
48 void clear()
49 {
50 rollback = false;
51 }
52
53 bool empty() const
54 {
55 return !rollback;
56 }
57
58 float getWidth() const
59 {
60 MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
61 return width;
62 }
63
64 size_t getCount() const
65 {
66 MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
67 return count;
68 }
69
70 size_t getPosition() const
71 {
72 MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
73 return position;
74 }
75
76 UString::utf32string::const_iterator getTextIter() const
77 {
78 MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
79 return space_point;
80 }
81
82 private:
83 size_t position{0};
84 UString::utf32string::const_iterator space_point;
85 size_t count{0};
86 float width{0};
87 bool rollback{false};
88 };
89
91 const UString::utf32string& _text,
92 IFont* _font,
93 int _height,
94 Align _align,
95 VertexColourType _format,
96 int _maxWidth)
97 {
98 mFontHeight = _height;
99
100 // массив для быстрой конвертации цветов
101 static const char convert_colour[64] = {
102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0};
104
105 mViewSize.clear();
106
107 RollBackPoint roll_back;
108 IntSize result;
109 float width = 0.0f;
110 size_t count = 0;
111 mLength = 0;
112 mLineInfo.clear();
113 LineInfo line_info;
114 int font_height = _font->getDefaultHeight();
115
116 UString::utf32string::const_iterator end = _text.end();
117 UString::utf32string::const_iterator index = _text.begin();
118
119 /*if (index == end)
120 return;*/
121
122 result.height += _height;
123
124 for (; index != end; ++index)
125 {
126 Char character = *index;
127
128 // new line
129 if (character == FontCodeType::CR || character == FontCodeType::NEL || character == FontCodeType::LF)
130 {
131 if (character == FontCodeType::CR)
132 {
133 UString::utf32string::const_iterator peeki = index;
134 ++peeki;
135 if ((peeki != end) && (*peeki == FontCodeType::LF))
136 index = peeki; // skip both as one newline
137 }
138
139 line_info.width = (int)std::ceil(width);
140 line_info.count = count;
141 mLength += line_info.count + 1;
142
143 result.height += _height;
144 setMax(result.width, line_info.width);
145 width = 0;
146 count = 0;
147
148 mLineInfo.push_back(line_info);
149 line_info.clear();
150
151 roll_back.clear();
152
153 continue;
154 }
155 // tag
156 if (character == L'#')
157 {
158 // check next character
159 ++index;
160 if (index == end)
161 {
162 --index;
163 continue;
164 }
165
166 character = *index;
167 // "##" converted to visible '#', change colour otherwise
168 if (character != L'#')
169 {
170 // read first character
171 uint32 colour = convert_colour[(character - 48) & 0x3F];
172
173 // and 5 more after '#'
174 for (char i = 0; i < 5; i++)
175 {
176 ++index;
177 if (index == end)
178 {
179 --index;
180 continue;
181 }
182 colour <<= 4;
183 colour += convert_colour[((*index) - 48) & 0x3F];
184 }
185
186 // convert to ABGR if we use that colour format
187 texture_utility::convertColour(colour, _format);
188
189 line_info.symbols.emplace_back(colour);
190
191 continue;
192 }
193 }
194
195 const GlyphInfo* info = _font->getGlyphInfo(character);
196
197 if (info == nullptr)
198 continue;
199
200 if (FontCodeType::Space == character || FontCodeType::Tab == character)
201 {
202 roll_back.set(line_info.symbols.size(), index, count, width);
203 }
204
205 float char_width = info->width;
206 float char_height = info->height;
207 float char_advance = info->advance;
208 float char_bearingX = info->bearingX;
209 float char_bearingY = info->bearingY;
210
211 if (_height != font_height)
212 {
213 float scale = (float)_height / font_height;
214
215 char_width *= scale;
216 char_height *= scale;
217 char_advance *= scale;
218 char_bearingX *= scale;
219 char_bearingY *= scale;
220 }
221
222 float char_fullAdvance = char_bearingX + char_advance;
223
224 // перенос слов
225 if (_maxWidth != -1 && (width + char_fullAdvance) > _maxWidth && !roll_back.empty())
226 {
227 // откатываем до последнего пробела
228 width = roll_back.getWidth();
229 count = roll_back.getCount();
230 index = roll_back.getTextIter();
231 line_info.symbols.erase(line_info.symbols.begin() + roll_back.getPosition(), line_info.symbols.end());
232
233 // запоминаем место отката, как полную строку
234 line_info.width = (int)std::ceil(width);
235 line_info.count = count;
236 mLength += line_info.count + 1;
237
238 result.height += _height;
239 setMax(result.width, line_info.width);
240 width = 0;
241 count = 0;
242
243 mLineInfo.push_back(line_info);
244 line_info.clear();
245
246 // отменяем откат
247 roll_back.clear();
248
249 continue;
250 }
251
252 line_info.symbols
253 .emplace_back(info->uvRect, char_width, char_height, char_advance, char_bearingX, char_bearingY);
254 width += char_fullAdvance;
255 count++;
256 }
257
258 line_info.width = (int)std::ceil(width);
259 line_info.count = count;
260 mLength += line_info.count;
261
262 mLineInfo.push_back(line_info);
263
264 setMax(result.width, line_info.width);
265
266 // теперь выравниванием строки
267 for (auto& line : mLineInfo)
268 {
269 if (_align.isRight())
270 line.offset = result.width - line.width;
271 else if (_align.isHCenter())
272 line.offset = (result.width - line.width) / 2;
273 }
274
275 mViewSize = result;
276 }
277
278 size_t TextView::getCursorPosition(const IntPoint& _value) const
279 {
280 size_t result = 0;
281 int top = 0;
282
283 for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
284 {
285 bool lastline = line + 1 == mLineInfo.end();
286
287 // наша строчка
288 if (top + mFontHeight <= _value.top && !lastline)
289 {
290 top += mFontHeight;
291 result += line->count + 1;
292 }
293 else
294 {
295 float left = (float)line->offset;
296 int count = 0;
297
298 // ищем символ
299 for (const auto& sym : line->symbols)
300 {
301 if (sym.isColour())
302 continue;
303
304 float fullAdvance = sym.getAdvance() + sym.getBearingX();
305 if (left + fullAdvance / 2.0f > _value.left)
306 {
307 break;
308 }
309 left += fullAdvance;
310 count++;
311 }
312
313 result += count;
314 break;
315 }
316 }
317
318 return result;
319 }
320
321 IntPoint TextView::getCursorPoint(size_t _position) const
322 {
323 setMin(_position, mLength);
324
325 size_t position = 0;
326 int top = 0;
327 float left = 0.0f;
328 for (const auto& line : mLineInfo)
329 {
330 left = (float)line.offset;
331 if (position + line.count >= _position)
332 {
333 for (const auto& sym : line.symbols)
334 {
335 if (sym.isColour())
336 continue;
337
338 if (position == _position)
339 break;
340
341 position++;
342 left += sym.getBearingX() + sym.getAdvance();
343 }
344 break;
345 }
346 position += line.count + 1;
347 top += mFontHeight;
348 }
349
350 return {(int)left, top};
351 }
352
354 {
355 return mViewSize;
356 }
357
359 {
360 return mLength;
361 }
362
364 {
365 return mLineInfo;
366 }
367
368} // namespace MyGUI
#define MYGUI_DEBUG_ASSERT(exp, dest)
virtual int getDefaultHeight() const =0
virtual const GlyphInfo * getGlyphInfo(Char _id) const =0
size_t getCursorPosition(const IntPoint &_value) const
IntPoint getCursorPoint(size_t _position) const
size_t getTextLength() const
void update(const UString::utf32string &_text, IFont *_font, int _height, Align _align, VertexColourType _format, int _maxWidth=-1)
const VectorLineInfo & getData() const
const IntSize & getViewSize() const
std::basic_string< unicode_char > utf32string
string type used for returning UTF-32 formatted data
void convertColour(uint32 &_colour, VertexColourType _format)
Convert from 32-bit ARGB to native colour (ABGR or ARGB)
uint32_t uint32
Definition MyGUI_Types.h:48
std::vector< LineInfo > VectorLineInfo
types::TPoint< int > IntPoint
Definition MyGUI_Types.h:27
unsigned int Char
Definition MyGUI_Types.h:50
types::TSize< int > IntSize
Definition MyGUI_Types.h:30
bool isRight() const
Definition MyGUI_Align.h:64
bool isHCenter() const
Definition MyGUI_Align.h:44
VectorCharInfo symbols