MyGUI  3.2.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, UString::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::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::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& _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::const_iterator end = _text.end();
125  UString::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::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)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.simbols.push_back( CharInfo(colour) );
201 
202  continue;
203  }
204  }
205 
206  GlyphInfo* info = _font->getGlyphInfo(character);
207 
208  if (info == nullptr)
209  continue;
210 
211  if (FontCodeType::Space == character)
212  {
213  roll_back.set(line_info.simbols.size(), index, count, width);
214  }
215  else if (FontCodeType::Tab == character)
216  {
217  roll_back.set(line_info.simbols.size(), index, count, width);
218  }
219 
220  float char_width = info->width;
221  float char_height = info->height;
222  float char_advance = info->advance;
223  float char_bearingX = info->bearingX;
224  float char_bearingY = info->bearingY;
225 
226  if (_height != font_height)
227  {
228  float scale = (float)_height / font_height;
229 
230  char_width *= scale;
231  char_height *= scale;
232  char_advance *= scale;
233  char_bearingX *= scale;
234  char_bearingY *= scale;
235  }
236 
237  float char_fullAdvance = char_bearingX + char_advance;
238 
239  // перенос слов
240  if (_maxWidth != -1
241  && (width + char_fullAdvance) > _maxWidth
242  && !roll_back.empty())
243  {
244  // откатываем до последнего пробела
245  width = roll_back.getWidth();
246  count = roll_back.getCount();
247  index = roll_back.getTextIter();
248  line_info.simbols.erase(line_info.simbols.begin() + roll_back.getPosition(), line_info.simbols.end());
249 
250  // запоминаем место отката, как полную строку
251  line_info.width = (int)ceil(width);
252  line_info.count = count;
253  mLength += line_info.count + 1;
254 
255  result.height += _height;
256  setMax(result.width, line_info.width);
257  width = 0;
258  count = 0;
259 
260  mLineInfo.push_back(line_info);
261  line_info.clear();
262 
263  // отменяем откат
264  roll_back.clear();
265 
266  continue;
267  }
268 
269  line_info.simbols.push_back(CharInfo(info->uvRect, char_width, char_height, char_advance, char_bearingX, char_bearingY));
270  width += char_fullAdvance;
271  count ++;
272  }
273 
274  line_info.width = (int)ceil(width);
275  line_info.count = count;
276  mLength += line_info.count;
277 
278  mLineInfo.push_back(line_info);
279 
280  setMax(result.width, line_info.width);
281 
282  // теперь выравниванием строки
283  for (VectorLineInfo::iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
284  {
285  if (_align.isRight())
286  line->offset = result.width - line->width;
287  else if (_align.isHCenter())
288  line->offset = (result.width - line->width) / 2;
289  }
290 
291  mViewSize = result;
292  }
293 
294  size_t TextView::getCursorPosition(const IntPoint& _value)
295  {
296  const int height = mFontHeight;
297  size_t result = 0;
298  int top = 0;
299 
300  for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
301  {
302  // это последняя строка
303  bool lastline = !(line + 1 != mLineInfo.end());
304 
305  // наша строчка
306  if (top + height > _value.top || lastline)
307  {
308  top += height;
309  float left = (float)line->offset;
310  int count = 0;
311 
312  // ищем символ
313  for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
314  {
315  if (sim->isColour())
316  continue;
317 
318  float fullAdvance = sim->getAdvance() + sim->getBearingX();
319  if (left + fullAdvance / 2.0f > _value.left)
320  {
321  break;
322  }
323  left += fullAdvance;
324  count ++;
325  }
326 
327  result += count;
328  break;
329  }
330 
331  if (!lastline)
332  {
333  top += height;
334  result += line->count + 1;
335  }
336  }
337 
338  return result;
339  }
340 
342  {
343  setMin(_position, mLength);
344 
345  size_t position = 0;
346  int top = 0;
347  float left = 0.0f;
348  for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
349  {
350  left = (float)line->offset;
351  if (position + line->count >= _position)
352  {
353  for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
354  {
355  if (sim->isColour())
356  continue;
357 
358  if (position == _position)
359  break;
360 
361  position ++;
362  left += sim->getBearingX() + sim->getAdvance();
363  }
364  break;
365  }
366  position += line->count + 1;
367  top += mFontHeight;
368  }
369 
370  return IntPoint((int)left, top);
371  }
372 
374  {
375  return mViewSize;
376  }
377 
378  size_t TextView::getTextLength() const
379  {
380  return mLength;
381  }
382 
384  {
385  return mLineInfo;
386  }
387 
388 } // namespace MyGUI