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