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