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)
226 {
227 if (!roll_back.empty())
228 {
229 // откатываем до последнего пробела
230 width = roll_back.getWidth();
231 count = roll_back.getCount();
232 index = roll_back.getTextIter();
233 line_info.symbols.erase(line_info.symbols.begin() + roll_back.getPosition(), line_info.symbols.end());
234 }
235
236 // запоминаем место отката, как полную строку
237 line_info.width = (int)std::ceil(width);
238 line_info.count = count;
239 mLength += line_info.count + 1;
240
241 result.height += _height;
242 setMax(result.width, line_info.width);
243 width = 0;
244 count = 0;
245
246 mLineInfo.push_back(line_info);
247 line_info.clear();
248
249 // отменяем откат
250 if (!roll_back.empty())
251 roll_back.clear();
252
253 continue;
254 }
255
256 line_info.symbols
257 .emplace_back(info->uvRect, char_width, char_height, char_advance, char_bearingX, char_bearingY);
258 width += char_fullAdvance;
259 count++;
260 }
261
262 line_info.width = (int)std::ceil(width);
263 line_info.count = count;
264 mLength += line_info.count;
265
266 mLineInfo.push_back(line_info);
267
268 setMax(result.width, line_info.width);
269
270 // теперь выравниванием строки
271 for (auto& line : mLineInfo)
272 {
273 if (_align.isRight())
274 line.offset = result.width - line.width;
275 else if (_align.isHCenter())
276 line.offset = (result.width - line.width) / 2;
277 }
278
279 mViewSize = result;
280 }
281
282 size_t TextView::getCursorPosition(const IntPoint& _value) const
283 {
284 size_t result = 0;
285 int top = 0;
286
287 for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
288 {
289 bool lastline = line + 1 == mLineInfo.end();
290
291 // наша строчка
292 if (top + mFontHeight <= _value.top && !lastline)
293 {
294 top += mFontHeight;
295 result += line->count + 1;
296 }
297 else
298 {
299 float left = (float)line->offset;
300 int count = 0;
301
302 // ищем символ
303 for (const auto& sym : line->symbols)
304 {
305 if (sym.isColour())
306 continue;
307
308 float fullAdvance = sym.getAdvance() + sym.getBearingX();
309 if (left + fullAdvance / 2.0f > _value.left)
310 {
311 break;
312 }
313 left += fullAdvance;
314 count++;
315 }
316
317 result += count;
318 break;
319 }
320 }
321
322 return result;
323 }
324
325 IntPoint TextView::getCursorPoint(size_t _position) const
326 {
327 setMin(_position, mLength);
328
329 size_t position = 0;
330 int top = 0;
331 float left = 0.0f;
332 for (const auto& line : mLineInfo)
333 {
334 left = (float)line.offset;
335 if (position + line.count >= _position)
336 {
337 for (const auto& sym : line.symbols)
338 {
339 if (sym.isColour())
340 continue;
341
342 if (position == _position)
343 break;
344
345 position++;
346 left += sym.getBearingX() + sym.getAdvance();
347 }
348 break;
349 }
350 position += line.count + 1;
351 top += mFontHeight;
352 }
353
354 return {(int)left, top};
355 }
356
358 {
359 return mViewSize;
360 }
361
363 {
364 return mLength;
365 }
366
368 {
369 return mLineInfo;
370 }
371
372} // 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