MyGUI  3.2.1
MyGUI_EditText.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_EditText.h"
9 #include "MyGUI_RenderItem.h"
10 #include "MyGUI_FontManager.h"
11 #include "MyGUI_RenderManager.h"
12 #include "MyGUI_LanguageManager.h"
13 #include "MyGUI_TextIterator.h"
14 #include "MyGUI_IRenderTarget.h"
15 #include "MyGUI_FontData.h"
16 #include "MyGUI_CommonStateInfo.h"
17 
18 namespace MyGUI
19 {
20 
21  const size_t VERTEX_IN_QUAD = 6;
23 
26  mEmptyView(false),
27  mCurrentColourNative(0x00FFFFFF),
28  mInverseColourNative(0x00000000),
29  mCurrentAlphaNative(0xFF000000),
30  mShadowColourNative(0x00000000),
31  mTextOutDate(false),
32  mTextAlign(Align::Default),
33  mColour(Colour::White),
34  mShadowColour(Colour::Black),
35  mAlpha(ALPHA_MAX),
36  mFont(nullptr),
37  mTexture(nullptr),
38  mFontHeight(0),
39  mBackgroundNormal(true),
40  mStartSelect(0),
41  mEndSelect(0),
42  mCursorPosition(0),
43  mVisibleCursor(false),
44  mInvertSelect(true),
45  mShadow(false),
46  mNode(nullptr),
47  mRenderItem(nullptr),
48  mCountVertex(SIMPLETEXT_COUNT_VERTEX),
49  mIsAddCursorWidth(true),
50  mShiftText(false),
51  mWordWrap(false),
52  mManualColour(false),
53  mOldWidth(0)
54  {
56 
59 
60  mCurrentColourNative = (mCurrentColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
61  mShadowColourNative = (mShadowColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
63  }
64 
66  {
67  }
68 
69  void EditText::setVisible(bool _visible)
70  {
71  if (mVisible == _visible)
72  return;
73  mVisible = _visible;
74 
75  if (nullptr != mNode)
77  }
78 
80  {
81  if (nullptr != mNode)
83  }
84 
85  void EditText::_setAlign(const IntSize& _oldsize)
86  {
87  if (mWordWrap)
88  {
89  // передается старая координата всегда
90  int width = mCroppedParent->getWidth();
91  if (mOldWidth != width)
92  {
93  mOldWidth = width;
94  mTextOutDate = true;
95  }
96  }
97 
98  // необходимо разобраться
99  bool need_update = true;//_update;
100 
101  // первоначальное выравнивание
102  if (mAlign.isHStretch())
103  {
104  // растягиваем
105  mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
106  need_update = true;
107  mIsMargin = true; // при изменении размеров все пересчитывать
108  }
109  else if (mAlign.isRight())
110  {
111  // двигаем по правому краю
112  mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
113  need_update = true;
114  }
115  else if (mAlign.isHCenter())
116  {
117  // выравнивание по горизонтали без растяжения
119  need_update = true;
120  }
121 
122  if (mAlign.isVStretch())
123  {
124  // растягиваем
126  need_update = true;
127  mIsMargin = true; // при изменении размеров все пересчитывать
128  }
129  else if (mAlign.isBottom())
130  {
131  // двигаем по нижнему краю
132  mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
133  need_update = true;
134  }
135  else if (mAlign.isVCenter())
136  {
137  // выравнивание по вертикали без растяжения
139  need_update = true;
140  }
141 
142  if (need_update)
143  {
145  _updateView();
146  }
147  }
148 
150  {
151  bool margin = _checkMargin();
152 
153  mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
154 
157 
158  // вьюпорт стал битым
159  if (margin)
160  {
161  // проверка на полный выход за границу
162  if (_checkOutside())
163  {
164  // запоминаем текущее состояние
165  mIsMargin = margin;
166 
167  // обновить перед выходом
168  if (nullptr != mNode)
170  return;
171  }
172  }
173 
174  // мы обрезаны или были обрезаны
175  if (mIsMargin || margin)
176  {
179  }
180 
181  // запоминаем текущее состояние
182  mIsMargin = margin;
183 
184  if (nullptr != mNode)
186  }
187 
188  void EditText::setCaption(const UString& _value)
189  {
190  mCaption = _value;
191  mTextOutDate = true;
192 
193  checkVertexSize();
194 
195  if (nullptr != mNode)
197  }
198 
199  void EditText::checkVertexSize()
200  {
201  // если вершин не хватит, делаем реалок, с учетом выделения * 2 и курсора
202  size_t need = (mCaption.size() * (mShadow ? 3 : 2) + 2) * VERTEX_IN_QUAD;
203  if (mCountVertex < need)
204  {
206  if (nullptr != mRenderItem)
208  }
209  }
210 
212  {
213  return mCaption;
214  }
215 
216  void EditText::setTextColour(const Colour& _value)
217  {
218  mManualColour = true;
219  _setTextColour(_value);
220  }
221 
222  void EditText::_setTextColour(const Colour& _value)
223  {
224  if (mColour == _value)
225  return;
226 
227  mColour = _value;
229 
231 
232  mCurrentColourNative = (mCurrentColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
234 
235  if (nullptr != mNode)
237  }
238 
240  {
241  return mColour;
242  }
243 
244  void EditText::setAlpha(float _value)
245  {
246  if (mAlpha == _value)
247  return;
248  mAlpha = _value;
249 
250  mCurrentAlphaNative = ((uint8)(mAlpha * 255) << 24);
251  mCurrentColourNative = (mCurrentColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
252  mShadowColourNative = (mShadowColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
254 
255  if (nullptr != mNode)
257  }
258 
259  float EditText::getAlpha() const
260  {
261  return mAlpha;
262  }
263 
264  void EditText::setFontName(const std::string& _value)
265  {
266  mTexture = 0;
268  if (mFont != nullptr)
269  {
271 
272  // если надо, устанавливаем дефолтный размер шрифта
273  if (mFont->getDefaultHeight() != 0)
274  {
276  }
277  }
278 
279  mTextOutDate = true;
280 
281  // если мы были приаттаченны, то удаляем себя
282  if (nullptr != mRenderItem)
283  {
285  mRenderItem = nullptr;
286  }
287 
288  // если есть текстура, то приаттачиваемся
289  if (nullptr != mTexture && nullptr != mNode)
290  {
291  mRenderItem = mNode->addToRenderItem(mTexture, false, false);
293  }
294 
295  if (nullptr != mNode)
297  }
298 
299  const std::string& EditText::getFontName() const
300  {
301  return mFont->getResourceName();
302  }
303 
304  void EditText::setFontHeight(int _value)
305  {
306  mFontHeight = _value;
307  mTextOutDate = true;
308 
309  if (nullptr != mNode)
311  }
312 
314  {
315  return mFontHeight;
316  }
317 
319  {
320  mNode = _node;
321  // если уже есть текстура, то атачимся, актуально для смены леера
322  if (nullptr != mTexture)
323  {
324  MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
325 
326  mRenderItem = mNode->addToRenderItem(mTexture, false, false);
328  }
329  }
330 
332  {
333  if (nullptr != mRenderItem)
334  {
336  mRenderItem = nullptr;
337  }
338  mNode = nullptr;
339  }
340 
342  {
343  return mStartSelect;
344  }
345 
347  {
348  return mEndSelect;
349  }
350 
351  void EditText::setTextSelection(size_t _start, size_t _end)
352  {
353  mStartSelect = _start;
354  mEndSelect = _end;
355 
356  if (nullptr != mNode)
358  }
359 
361  {
362  return mBackgroundNormal;
363  }
364 
365  void EditText::setSelectBackground(bool _normal)
366  {
367  if (mBackgroundNormal == _normal)
368  return;
369  mBackgroundNormal = _normal;
370 
371  if (nullptr != mNode)
373  }
374 
376  {
377  return mVisibleCursor;
378  }
379 
380  void EditText::setVisibleCursor(bool _value)
381  {
382  if (mVisibleCursor == _value)
383  return;
384  mVisibleCursor = _value;
385 
386  if (nullptr != mNode)
388  }
389 
391  {
392  return mCursorPosition;
393  }
394 
395  void EditText::setCursorPosition(size_t _index)
396  {
397  if (mCursorPosition == _index)
398  return;
399  mCursorPosition = _index;
400 
401  if (nullptr != mNode)
403  }
404 
406  {
407  mTextAlign = _value;
408 
409  if (nullptr != mNode)
411  }
412 
414  {
415  return mTextAlign;
416  }
417 
419  {
420  // если нуно обновить, или изменились пропорции экрана
421  if (mTextOutDate)
422  updateRawData();
423 
424  IntSize size = mTextView.getViewSize();
425  // плюс размер курсора
426  if (mIsAddCursorWidth)
427  size.width += 2;
428 
429  if (mShadow)
430  {
431  if (!mIsAddCursorWidth)
432  size.width ++;
433  size.height ++;
434  }
435 
436  return size;
437  }
438 
439  void EditText::setViewOffset(const IntPoint& _point)
440  {
441  mViewOffset = _point;
442 
443  if (nullptr != mNode)
445  }
446 
448  {
449  return mViewOffset;
450  }
451 
452  size_t EditText::getCursorPosition(const IntPoint& _point)
453  {
454  if (nullptr == mFont)
455  return 0;
456 
457  if (mTextOutDate)
458  updateRawData();
459 
460  IntPoint point = _point;
462  point += mViewOffset;
463  point -= mCoord.point();
464 
465  return mTextView.getCursorPosition(point);
466  }
467 
469  {
470  if (nullptr == mFont)
471  return IntCoord();
472 
473  if (mTextOutDate)
474  updateRawData();
475 
476  IntPoint point = mTextView.getCursorPoint(_position);
478  point -= mViewOffset;
479  point += mCoord.point();
480 
481  return IntCoord(point.left, point.top, 2, mFontHeight);
482  }
483 
484  void EditText::setShiftText(bool _value)
485  {
486  if (mShiftText == _value)
487  return;
488  mShiftText = _value;
489 
490  if (nullptr != mNode)
492  }
493 
494  void EditText::setWordWrap(bool _value)
495  {
496  mWordWrap = _value;
497  mTextOutDate = true;
498 
499  if (nullptr != mNode)
501  }
502 
504  {
505  if (nullptr == mFont)
506  return;
507  // сбрасывам флаги
508  mTextOutDate = false;
509 
510  int width = -1;
511  if (mWordWrap)
512  {
513  width = mCoord.width;
514  // обрезать слова нужно по шарине, которую мы реально используем
515  if (mIsAddCursorWidth)
516  width -= 2;
517  }
518 
520  }
521 
523  {
524  EditTextStateInfo* data = _data->castType<EditTextStateInfo>();
525  if (!mManualColour && data->getColour() != Colour::Zero)
526  _setTextColour(data->getColour());
527  setShiftText(data->getShift());
528  }
529 
531  {
532  if (nullptr == mFont || !mVisible || mEmptyView)
533  return;
534 
536  updateRawData();
537 
539 
540  const RenderTargetInfo& renderTargetInfo = mRenderItem->getRenderTarget()->getInfo();
541 
542  // колличество отрисованных вершин
543  size_t vertexCount = 0;
544 
545  // текущие цвета
546  uint32 colour = mCurrentColourNative;
547  uint32 inverseColour = mInverseColourNative;
548  uint32 selectedColour = mInvertSelect ? inverseColour : colour | 0x00FFFFFF;
549 
550  const VectorLineInfo& textViewData = mTextView.getData();
551 
552  float top = (float)(-mViewOffset.top + mCoord.top);
553 
554  FloatRect vertexRect;
555 
557 
558  size_t index = 0;
559 
560  for (VectorLineInfo::const_iterator line = textViewData.begin(); line != textViewData.end(); ++line)
561  {
562  float left = (float)(line->offset - mViewOffset.left + mCoord.left);
563 
564  for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
565  {
566  if (sim->isColour())
567  {
568  colour = sim->getColour() | (colour & 0xFF000000);
569  inverseColour = colour ^ 0x00FFFFFF;
570  selectedColour = mInvertSelect ? inverseColour : colour | 0x00FFFFFF;
571  continue;
572  }
573 
574  // смещение текстуры для фона
575  bool select = index >= mStartSelect && index < mEndSelect;
576 
577  float fullAdvance = sim->getBearingX() + sim->getAdvance();
578 
579  // Render the selection, if any, first.
580  if (select)
581  {
582  vertexRect.set(left, top, left + fullAdvance, top + (float)mFontHeight);
583 
584  drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, selectedUVRect, selectedColour);
585  }
586 
587  // Render the glyph shadow, if any.
588  if (mShadow)
589  {
590  vertexRect.left = left + sim->getBearingX() + 1.0f;
591  vertexRect.top = top + sim->getBearingY() + 1.0f;
592  vertexRect.right = vertexRect.left + sim->getWidth();
593  vertexRect.bottom = vertexRect.top + sim->getHeight();
594 
595  drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, sim->getUVRect(), mShadowColourNative);
596  }
597 
598  // Render the glyph itself.
599  vertexRect.left = left + sim->getBearingX();
600  vertexRect.top = top + sim->getBearingY();
601  vertexRect.right = vertexRect.left + sim->getWidth();
602  vertexRect.bottom = vertexRect.top + sim->getHeight();
603 
604  drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, sim->getUVRect(), (!select || !mInvertSelect) ? colour : inverseColour);
605 
606  left += fullAdvance;
607  ++index;
608  }
609 
610  top += mFontHeight;
611  ++index;
612  }
613 
614  // Render the cursor, if any, last.
615  if (mVisibleCursor)
616  {
618  GlyphInfo* cursorGlyph = mFont->getGlyphInfo(static_cast<Char>(FontCodeType::Cursor));
619  vertexRect.set((float)point.left, (float)point.top, (float)point.left + cursorGlyph->width, (float)(point.top + mFontHeight));
620 
621  drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, cursorGlyph->uvRect, mCurrentColourNative | 0x00FFFFFF);
622  }
623 
624  // колличество реально отрисованных вершин
625  mRenderItem->setLastVertexCount(vertexCount);
626  }
627 
628  void EditText::setInvertSelected(bool _value)
629  {
630  if (mInvertSelect == _value)
631  return;
632  mInvertSelect = _value;
633 
634  if (nullptr != mNode)
636  }
637 
639  {
640  return mInvertSelect;
641  }
642 
643  bool EditText::getShadow() const
644  {
645  return mShadow;
646  }
647 
648  void EditText::setShadow(bool _value)
649  {
650  mShadow = _value;
651  mTextOutDate = true;
652 
653  checkVertexSize();
654 
655  if (nullptr != mNode)
657  }
658 
659  void EditText::setShadowColour(const Colour& _value)
660  {
661  mShadowColour = _value;
663 
665 
666  mShadowColourNative = (mShadowColourNative & 0x00FFFFFF) | (mCurrentAlphaNative & 0xFF000000);
667 
668  if (nullptr != mNode)
670  }
671 
673  {
674  return mShadowColour;
675  }
676 
677  void EditText::drawQuad(
678  Vertex*& _vertex,
679  size_t& _vertexCount,
680  const FloatRect& _vertexRect,
681  float _vertexZ,
682  const FloatRect& _textureRect,
683  uint32 _colour) const
684  {
685  _vertex[0].x = _vertexRect.left;
686  _vertex[0].y = _vertexRect.top;
687  _vertex[0].z = _vertexZ;
688  _vertex[0].colour = _colour;
689  _vertex[0].u = _textureRect.left;
690  _vertex[0].v = _textureRect.top;
691 
692  _vertex[2].x = _vertexRect.left;
693  _vertex[2].y = _vertexRect.bottom;
694  _vertex[2].z = _vertexZ;
695  _vertex[2].colour = _colour;
696  _vertex[2].u = _textureRect.left;
697  _vertex[2].v = _textureRect.bottom;
698 
699  _vertex[1].x = _vertexRect.right;
700  _vertex[1].y = _vertexRect.top;
701  _vertex[1].z = _vertexZ;
702  _vertex[1].colour = _colour;
703  _vertex[1].u = _textureRect.right;
704  _vertex[1].v = _textureRect.top;
705 
706  _vertex[3].x = _vertexRect.right;
707  _vertex[3].y = _vertexRect.top;
708  _vertex[3].z = _vertexZ;
709  _vertex[3].colour = _colour;
710  _vertex[3].u = _textureRect.right;
711  _vertex[3].v = _textureRect.top;
712 
713  _vertex[5].x = _vertexRect.left;
714  _vertex[5].y = _vertexRect.bottom;
715  _vertex[5].z = _vertexZ;
716  _vertex[5].colour = _colour;
717  _vertex[5].u = _textureRect.left;
718  _vertex[5].v = _textureRect.bottom;
719 
720  _vertex[4].x = _vertexRect.right;
721  _vertex[4].y = _vertexRect.bottom;
722  _vertex[4].z = _vertexZ;
723  _vertex[4].colour = _colour;
724  _vertex[4].u = _textureRect.right;
725  _vertex[4].v = _textureRect.bottom;
726 
727  _vertex += VERTEX_IN_QUAD;
728  _vertexCount += VERTEX_IN_QUAD;
729  }
730 
731  void EditText::drawGlyph(
732  const RenderTargetInfo& _renderTargetInfo,
733  Vertex*& _vertex,
734  size_t& _vertexCount,
735  FloatRect _vertexRect,
736  FloatRect _textureRect,
737  uint32 _colour) const
738  {
739  // символ залазиет влево
740  float leftClip = (float)mCurrentCoord.left - _vertexRect.left;
741  if (leftClip > 0.0f)
742  {
743  if ((float)mCurrentCoord.left < _vertexRect.right)
744  {
745  _textureRect.left += _textureRect.width() * leftClip / _vertexRect.width();
746  _vertexRect.left += leftClip;
747  }
748  else
749  {
750  return;
751  }
752  }
753 
754  // символ залазиет вправо
755  float rightClip = _vertexRect.right - (float)mCurrentCoord.right();
756  if (rightClip > 0.0f)
757  {
758  if (_vertexRect.left < (float)mCurrentCoord.right())
759  {
760  _textureRect.right -= _textureRect.width() * rightClip / _vertexRect.width();
761  _vertexRect.right -= rightClip;
762  }
763  else
764  {
765  return;
766  }
767  }
768 
769  // символ залазиет вверх
770  float topClip = (float)mCurrentCoord.top - _vertexRect.top;
771  if (topClip > 0.0f)
772  {
773  if ((float)mCurrentCoord.top < _vertexRect.bottom)
774  {
775  _textureRect.top += _textureRect.height() * topClip / _vertexRect.height();
776  _vertexRect.top += topClip;
777  }
778  else
779  {
780  return;
781  }
782  }
783 
784  // символ залазиет вниз
785  float bottomClip = _vertexRect.bottom - (float)mCurrentCoord.bottom();
786  if (bottomClip > 0.0f)
787  {
788  if (_vertexRect.top < (float)mCurrentCoord.bottom())
789  {
790  _textureRect.bottom -= _textureRect.height() * bottomClip / _vertexRect.height();
791  _vertexRect.bottom -= bottomClip;
792  }
793  else
794  {
795  return;
796  }
797  }
798 
799  float pix_left = mCroppedParent->getAbsoluteLeft() - _renderTargetInfo.leftOffset + _vertexRect.left;
800  float pix_top = mCroppedParent->getAbsoluteTop() - _renderTargetInfo.topOffset + (mShiftText ? 1.0f : 0.0f) + _vertexRect.top;
801 
802  FloatRect vertexRect(
803  ((_renderTargetInfo.pixScaleX * pix_left + _renderTargetInfo.hOffset) * 2.0f) - 1.0f,
804  -(((_renderTargetInfo.pixScaleY * pix_top + _renderTargetInfo.vOffset) * 2.0f) - 1.0f),
805  ((_renderTargetInfo.pixScaleX * (pix_left + _vertexRect.width()) + _renderTargetInfo.hOffset) * 2.0f) - 1.0f,
806  -(((_renderTargetInfo.pixScaleY * (pix_top + _vertexRect.height()) + _renderTargetInfo.vOffset) * 2.0f) - 1.0f));
807 
808  drawQuad(_vertex, _vertexCount, vertexRect, mNode->getNodeDepth(), _textureRect, _colour);
809  }
810 
811 } // namespace MyGUI