MyGUI  3.2.0
MyGUI_TextView.cpp
Go to the documentation of this file.
1 
6 /*
7  This file is part of MyGUI.
8 
9  MyGUI is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  MyGUI is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
21 */
22 #include "MyGUI_Precompiled.h"
23 #include "MyGUI_TextView.h"
24 
25 namespace MyGUI
26 {
27 
28  namespace
29  {
30 
31  template<typename T>
32  void setMin(T& _var, const T& _newValue)
33  {
34  if (_newValue < _var)
35  _var = _newValue;
36  }
37 
38  template<typename T>
39  void setMax(T& _var, const T& _newValue)
40  {
41  if (_var < _newValue)
42  _var = _newValue;
43  }
44 
45  }
46 
47  class RollBackPoint
48  {
49  public:
50  RollBackPoint() :
51  position(0),
52  count(0),
53  width(0),
54  rollback(false)
55  {
56  }
57 
58  void set(size_t _position, UString::const_iterator& _space_point, size_t _count, float _width)
59  {
60  position = _position;
61  space_point = _space_point;
62  count = _count;
63  width = _width;
64  rollback = true;
65  }
66 
67  void clear()
68  {
69  rollback = false;
70  }
71 
72  bool empty() const
73  {
74  return !rollback;
75  }
76 
77  float getWidth() const
78  {
79  MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
80  return width;
81  }
82 
83  size_t getCount() const
84  {
85  MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
86  return count;
87  }
88 
89  size_t getPosition() const
90  {
91  MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
92  return position;
93  }
94 
95  UString::const_iterator getTextIter() const
96  {
97  MYGUI_DEBUG_ASSERT(rollback, "rollback point not valid");
98  return space_point;
99  }
100 
101  private:
102  size_t position;
103  UString::const_iterator space_point;
104  size_t count;
105  float width;
106  bool rollback;
107  };
108 
110  mLength(0),
111  mFontHeight(0)
112  {
113  }
114 
115  void TextView::update(const UString& _text, IFont* _font, int _height, Align _align, VertexColourType _format, int _maxWidth)
116  {
117  mFontHeight = _height;
118 
119  // массив для быстрой конвертации цветов
120  static const char convert_colour[64] =
121  {
122  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
123  0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125  0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0
126  };
127 
128  mViewSize.clear();
129 
130  RollBackPoint roll_back;
131  IntSize result;
132  float width = 0.0f;
133  size_t count = 0;
134  mLength = 0;
135  mLineInfo.clear();
136  LineInfo line_info;
137  int font_height = _font->getDefaultHeight();
138 
139  UString::const_iterator end = _text.end();
140  UString::const_iterator index = _text.begin();
141 
142  /*if (index == end)
143  return;*/
144 
145  result.height += _height;
146 
147  for (; index != end; ++index)
148  {
149  Char character = *index;
150 
151  // новая строка
152  if (character == FontCodeType::CR
153  || character == FontCodeType::NEL
154  || character == FontCodeType::LF)
155  {
156  if (character == FontCodeType::CR)
157  {
158  UString::const_iterator peeki = index;
159  ++peeki;
160  if ((peeki != end) && (*peeki == FontCodeType::LF))
161  index = peeki; // skip both as one newline
162  }
163 
164  line_info.width = (int)ceil(width);
165  line_info.count = count;
166  mLength += line_info.count + 1;
167 
168  result.height += _height;
169  setMax(result.width, line_info.width);
170  width = 0;
171  count = 0;
172 
173  mLineInfo.push_back(line_info);
174  line_info.clear();
175 
176  // отменяем откат
177  roll_back.clear();
178 
179  continue;
180  }
181  // тег
182  else if (character == L'#')
183  {
184  // берем следующий символ
185  ++ index;
186  if (index == end)
187  {
188  --index; // это защита
189  continue;
190  }
191 
192  character = *index;
193  // если два подряд, то рисуем один шарп, если нет то меняем цвет
194  if (character != L'#')
195  {
196  // парсим первый символ
197  uint32 colour = convert_colour[(character - 48) & 0x3F];
198 
199  // и еще пять символов после шарпа
200  for (char i = 0; i < 5; i++)
201  {
202  ++ index;
203  if (index == end)
204  {
205  --index; // это защита
206  continue;
207  }
208  colour <<= 4;
209  colour += convert_colour[ ((*index) - 48) & 0x3F ];
210  }
211 
212  // если нужно, то меняем красный и синий компоненты
213  texture_utility::convertColour(colour, _format);
214 
215  line_info.simbols.push_back( CharInfo(colour) );
216 
217  continue;
218  }
219  }
220 
221  GlyphInfo* info = _font->getGlyphInfo(character);
222 
223  if (info == nullptr)
224  continue;
225 
226  if (FontCodeType::Space == character)
227  {
228  roll_back.set(line_info.simbols.size(), index, count, width);
229  }
230  else if (FontCodeType::Tab == character)
231  {
232  roll_back.set(line_info.simbols.size(), index, count, width);
233  }
234 
235  float char_width = info->width;
236  float char_height = info->height;
237  float char_advance = info->advance;
238  float char_bearingX = info->bearingX;
239  float char_bearingY = info->bearingY;
240 
241  if (_height != font_height)
242  {
243  float scale = (float)_height / font_height;
244 
245  char_width *= scale;
246  char_height *= scale;
247  char_advance *= scale;
248  char_bearingX *= scale;
249  char_bearingY *= scale;
250  }
251 
252  float char_fullAdvance = char_bearingX + char_advance;
253 
254  // перенос слов
255  if (_maxWidth != -1
256  && (width + char_fullAdvance) > _maxWidth
257  && !roll_back.empty())
258  {
259  // откатываем до последнего пробела
260  width = roll_back.getWidth();
261  count = roll_back.getCount();
262  index = roll_back.getTextIter();
263  line_info.simbols.erase(line_info.simbols.begin() + roll_back.getPosition(), line_info.simbols.end());
264 
265  // запоминаем место отката, как полную строку
266  line_info.width = (int)ceil(width);
267  line_info.count = count;
268  mLength += line_info.count + 1;
269 
270  result.height += _height;
271  setMax(result.width, line_info.width);
272  width = 0;
273  count = 0;
274 
275  mLineInfo.push_back(line_info);
276  line_info.clear();
277 
278  // отменяем откат
279  roll_back.clear();
280 
281  continue;
282  }
283 
284  line_info.simbols.push_back(CharInfo(info->uvRect, char_width, char_height, char_advance, char_bearingX, char_bearingY));
285  width += char_fullAdvance;
286  count ++;
287  }
288 
289  line_info.width = (int)ceil(width);
290  line_info.count = count;
291  mLength += line_info.count;
292 
293  mLineInfo.push_back(line_info);
294 
295  setMax(result.width, line_info.width);
296 
297  // теперь выравниванием строки
298  for (VectorLineInfo::iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
299  {
300  if (_align.isRight())
301  line->offset = result.width - line->width;
302  else if (_align.isHCenter())
303  line->offset = (result.width - line->width) / 2;
304  }
305 
306  mViewSize = result;
307  }
308 
309  size_t TextView::getCursorPosition(const IntPoint& _value)
310  {
311  const int height = mFontHeight;
312  size_t result = 0;
313  int top = 0;
314 
315  for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
316  {
317  // это последняя строка
318  bool lastline = !(line + 1 != mLineInfo.end());
319 
320  // наша строчка
321  if (top + height > _value.top || lastline)
322  {
323  top += height;
324  float left = (float)line->offset;
325  int count = 0;
326 
327  // ищем символ
328  for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
329  {
330  if (sim->isColour())
331  continue;
332 
333  float fullAdvance = sim->getAdvance() + sim->getBearingX();
334  if (left + fullAdvance / 2.0f > _value.left)
335  {
336  break;
337  }
338  left += fullAdvance;
339  count ++;
340  }
341 
342  result += count;
343  break;
344  }
345 
346  if (!lastline)
347  {
348  top += height;
349  result += line->count + 1;
350  }
351  }
352 
353  return result;
354  }
355 
357  {
358  setMin(_position, mLength);
359 
360  size_t position = 0;
361  int top = 0;
362  float left = 0.0f;
363  for (VectorLineInfo::const_iterator line = mLineInfo.begin(); line != mLineInfo.end(); ++line)
364  {
365  left = (float)line->offset;
366  if (position + line->count >= _position)
367  {
368  for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
369  {
370  if (sim->isColour())
371  continue;
372 
373  if (position == _position)
374  break;
375 
376  position ++;
377  left += sim->getBearingX() + sim->getAdvance();
378  }
379  break;
380  }
381  position += line->count + 1;
382  top += mFontHeight;
383  }
384 
385  return IntPoint((int)left, top);
386  }
387 
389  {
390  return mViewSize;
391  }
392 
393  size_t TextView::getTextLength() const
394  {
395  return mLength;
396  }
397 
399  {
400  return mLineInfo;
401  }
402 
403 } // namespace MyGUI
size_t getTextLength() const
const IntSize & getViewSize() const
unsigned int uint32
Definition: MyGUI_Types.h:63
__inline void convertColour(uint32 &_colour, VertexColourType _format)
std::vector< LineInfo > VectorLineInfo
const VectorLineInfo & getData() const
VectorCharInfo simbols
_const_fwd_iterator const_iterator
const iterator
const forward iterator for UString
bool isHCenter() const
Definition: MyGUI_Align.h:59
iterator begin()
returns an iterator to the first element of the string
bool isRight() const
Definition: MyGUI_Align.h:79
unsigned int Char
Definition: MyGUI_Types.h:66
size_t getCursorPosition(const IntPoint &_value)
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
IntPoint getCursorPoint(size_t _position)
#define MYGUI_DEBUG_ASSERT(exp, dest)
virtual int getDefaultHeight()=0
iterator end()
returns an iterator just past the end of the string
virtual GlyphInfo * getGlyphInfo(Char _id)=0
void update(const UString &_text, IFont *_font, int _height, Align _align, VertexColourType _format, int _maxWidth=-1)
types::TPoint< int > IntPoint
Definition: MyGUI_Types.h:41