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