MyGUI  3.0.1
MyGUI_EditText.cpp
Go to the documentation of this file.
1 
7 /*
8  This file is part of MyGUI.
9 
10  MyGUI is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  MyGUI is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #include "MyGUI_Precompiled.h"
24 #include "MyGUI_EditText.h"
25 #include "MyGUI_RenderItem.h"
26 #include "MyGUI_FontManager.h"
27 #include "MyGUI_RenderManager.h"
28 #include "MyGUI_LanguageManager.h"
29 #include "MyGUI_TextIterator.h"
30 #include "MyGUI_IRenderTarget.h"
31 #include "MyGUI_FontData.h"
32 #include "MyGUI_CommonStateInfo.h"
33 
34 namespace MyGUI
35 {
36 
37  const size_t VERTEX_IN_QUAD = 6;
39 
41  MyGUI::Vertex*& _buff,
42  float v_left,
43  float v_top,
44  float v_rignt,
45  float v_bottom,
46  float v_z,
47  MyGUI::uint32 _colour,
48  float t_left,
49  float t_top,
50  float t_right,
51  float t_bottom,
52  size_t& _count)
53  {
54  _buff[0].x = v_left;
55  _buff[0].y = v_top;
56  _buff[0].z = v_z;
57  _buff[0].colour = _colour;
58  _buff[0].u = t_left;
59  _buff[0].v = t_top;
60 
61  _buff[1].x = v_left;
62  _buff[1].y = v_bottom;
63  _buff[1].z = v_z;
64  _buff[1].colour = _colour;
65  _buff[1].u = t_left;
66  _buff[1].v = t_bottom;
67 
68  _buff[2].x = v_rignt;
69  _buff[2].y = v_top;
70  _buff[2].z = v_z;
71  _buff[2].colour = _colour;
72  _buff[2].u = t_right;
73  _buff[2].v = t_top;
74 
75  _buff[3].x = v_rignt;
76  _buff[3].y = v_top;
77  _buff[3].z = v_z;
78  _buff[3].colour = _colour;
79  _buff[3].u = t_right;
80  _buff[3].v = t_top;
81 
82  _buff[4].x = v_left;
83  _buff[4].y = v_bottom;
84  _buff[4].z = v_z;
85  _buff[4].colour = _colour;
86  _buff[4].u = t_left;
87  _buff[4].v = t_bottom;
88 
89  _buff[5].x = v_rignt;
90  _buff[5].y = v_bottom;
91  _buff[5].z = v_z;
92  _buff[5].colour = _colour;
93  _buff[5].u = t_right;
94  _buff[5].v = t_bottom;
95 
96  _buff += VERTEX_IN_QUAD;
97  _count += VERTEX_IN_QUAD;
98  }
99 
101  ISubWidgetText(),
102  mEmptyView(false),
103  mCurrentColour(0x00FFFFFF),
104  mInverseColour(0x00000000),
105  mCurrentAlpha(0xFF000000),
106  mTextOutDate(false),
107  mTextAlign(Align::Default),
108  mColour(Colour::White),
109  mAlpha(ALPHA_MAX),
110  mFont(nullptr),
111  mTexture(nullptr),
112  mFontHeight(0),
113  mBackgroundNormal(true),
114  mStartSelect(0),
115  mEndSelect(0),
116  mCursorPosition(0),
117  mVisibleCursor(false),
118  mInvertSelect(true),
119  mNode(nullptr),
120  mRenderItem(nullptr),
121  mCountVertex(SIMPLETEXT_COUNT_VERTEX),
122  mIsAddCursorWidth(true),
123  mShiftText(false),
124  mWordWrap(false),
125  mOldWidth(0)
126  {
128 
131 
132  mCurrentColour = (mCurrentColour & 0x00FFFFFF) | mCurrentAlpha;
133  mInverseColour = mCurrentColour ^ 0x00FFFFFF;
134  }
135 
137  {
138  }
139 
140  void EditText::setVisible(bool _visible)
141  {
142  if (mVisible == _visible) return;
143  mVisible = _visible;
144 
145  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
146  }
147 
149  {
150  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
151  }
152 
153  void EditText::_setAlign(const IntCoord& _oldcoord, bool _update)
154  {
155  _setAlign(_oldcoord.size(), _update);
156  }
157 
158  void EditText::_setAlign(const IntSize& _oldsize, bool _update)
159  {
160 
161  if (mWordWrap)
162  {
163  // передается старая координата всегда
164  int width = mCroppedParent->getWidth();
165  if (mOldWidth != width)
166  {
167  mOldWidth = width;
168  mTextOutDate = true;
169  }
170  }
171 
172  // необходимо разобраться
173  bool need_update = true;//_update;
174 
175  // первоначальное выравнивание
176  if (mAlign.isHStretch())
177  {
178  // растягиваем
179  mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
180  need_update = true;
181  mIsMargin = true; // при изменении размеров все пересчитывать
182  }
183  else if (mAlign.isRight())
184  {
185  // двигаем по правому краю
186  mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
187  need_update = true;
188  }
189  else if (mAlign.isHCenter())
190  {
191  // выравнивание по горизонтали без растяжения
193  need_update = true;
194  }
195 
196  if (mAlign.isVStretch())
197  {
198  // растягиваем
200  need_update = true;
201  mIsMargin = true; // при изменении размеров все пересчитывать
202  }
203  else if (mAlign.isBottom())
204  {
205  // двигаем по нижнему краю
206  mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
207  need_update = true;
208  }
209  else if (mAlign.isVCenter())
210  {
211  // выравнивание по вертикали без растяжения
213  need_update = true;
214  }
215 
216  if (need_update)
217  {
219  _updateView();
220  }
221 
222  }
223 
225  {
226  bool margin = _checkMargin();
227 
228  mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
229 
232 
233  // вьюпорт стал битым
234  if (margin)
235  {
236  // проверка на полный выход за границу
237  if (_checkOutside())
238  {
239  // запоминаем текущее состояние
240  mIsMargin = margin;
241 
242  // обновить перед выходом
243  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
244  return;
245  }
246  }
247 
248  // мы обрезаны или были обрезаны
249  if ((mIsMargin) || (margin))
250  {
253  }
254 
255  // запоминаем текущее состояние
256  mIsMargin = margin;
257 
258  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
259  }
260 
261  void EditText::setCaption(const UString& _value)
262  {
263  mCaption = _value;
264  mTextOutDate = true;
265 
266  // если вершин не хватит, делаем реалок, с учетом выделения * 2 и курсора
267  size_t need = (mCaption.size() * 2 + 2) * VERTEX_IN_QUAD;
268  if (mCountVertex < need)
269  {
271  if (nullptr != mRenderItem) mRenderItem->reallockDrawItem(this, mCountVertex);
272  }
273  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
274  }
275 
277  {
278  return mCaption;
279  }
280 
281  void EditText::setTextColour(const Colour& _value)
282  {
283  if (mColour == _value) return;
284  mColour = _value;
286 
288 
289  mCurrentColour = (mCurrentColour & 0x00FFFFFF) | mCurrentAlpha;
290  mInverseColour = mCurrentColour ^ 0x00FFFFFF;
291 
292  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
293  }
294 
296  {
297  return mColour;
298  }
299 
300  void EditText::setAlpha(float _value)
301  {
302  if (mAlpha == _value) return;
303  mAlpha = _value;
304  mCurrentAlpha = ((uint8)(mAlpha*255) << 24);
305  mCurrentColour = (mCurrentColour & 0x00FFFFFF) | mCurrentAlpha;
306  mInverseColour = mCurrentColour ^ 0x00FFFFFF;
307 
308  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
309  }
310 
312  {
313  return mAlpha;
314  }
315 
316  void EditText::setFontName(const std::string& _value)
317  {
318  mTexture = 0;
320  if (mFont != nullptr)
321  {
323 
324  // если надо, устанавливаем дефолтный размер шрифта
325  if (mFont->getDefaultHeight() != 0)
326  {
328  }
329  }
330 
331  mTextOutDate = true;
332 
333  // если мы были приаттаченны, то удаляем себя
334  if (nullptr != mRenderItem)
335  {
337  mRenderItem = nullptr;
338  }
339 
340  // если есть текстура, то приаттачиваемся
341  if (nullptr != mTexture && nullptr != mNode)
342  {
345  }
346 
347  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
348  }
349 
350  const std::string& EditText::getFontName()
351  {
352  return mFont->getResourceName();
353  }
354 
355  void EditText::setFontHeight(int _value)
356  {
357  mFontHeight = _value;
358  mTextOutDate = true;
359  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
360  }
361 
363  {
364  return mFontHeight;
365  }
366 
368  {
369  mNode = _node;
370  // если уже есть текстура, то атачимся, актуально для смены леера
371  if (nullptr != mTexture)
372  {
373  MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
374 
377  }
378  }
379 
381  {
382  if (nullptr != mRenderItem)
383  {
385  mRenderItem = nullptr;
386  }
387  mNode = nullptr;
388  }
389 
391  {
392  return mStartSelect;
393  }
394 
396  {
397  return mEndSelect;
398  }
399 
400  void EditText::setTextSelection(size_t _start, size_t _end)
401  {
402  mStartSelect=_start;
403  mEndSelect=_end;
404  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
405  }
406 
408  {
409  return mBackgroundNormal;
410  }
411 
412  void EditText::setSelectBackground(bool _normal)
413  {
414  if (mBackgroundNormal == _normal) return;
415  mBackgroundNormal = _normal;
416  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
417  }
418 
420  {
421  return mVisibleCursor;
422  }
423 
424  void EditText::setVisibleCursor(bool _value)
425  {
426  if (mVisibleCursor == _value) return;
427  mVisibleCursor = _value;
428  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
429  }
430 
432  {
433  return mCursorPosition;
434  }
435 
436  void EditText::setCursorPosition(size_t _index)
437  {
438  if (mCursorPosition == _index) return;
439  mCursorPosition = _index;
440  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
441  }
442 
444  {
445  mTextAlign = _value;
446  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
447  }
448 
450  {
451  return mTextAlign;
452  }
453 
455  {
456  // если нуно обновить, или изменились пропорции экрана
458 
459  IntSize size = mTextView.getViewSize();
460  // плюс размер курсора
461  if (mIsAddCursorWidth)
462  size.width += 2;
463  return size;
464  }
465 
466  void EditText::setViewOffset(const IntPoint& _point)
467  {
468  mViewOffset = _point;
469  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
470  }
471 
473  {
474  return mViewOffset;
475  }
476 
477  size_t EditText::getCursorPosition(const IntPoint& _point)
478  {
479  if (nullptr == mFont) return 0;
481 
482  IntPoint point = _point;
484  point += mViewOffset;
485  point -= mCoord.point();
486 
487  return mTextView.getCursorPosition(point);
488  }
489 
491  {
492  if (nullptr == mFont) return IntCoord();
494 
495  IntPoint point = mTextView.getCursorPoint(_position);
497  point -= mViewOffset;
498  point += mCoord.point();
499 
500  return IntCoord(point.left, point.top, 2, mFontHeight);
501  }
502 
503  void EditText::setShiftText(bool _value)
504  {
505  if (mShiftText == _value) return;
506  mShiftText = _value;
507  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
508  }
509 
510  void EditText::setWordWrap(bool _value)
511  {
512  mWordWrap = _value;
513  mTextOutDate = true;
514  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
515  }
516 
518  {
519  if (nullptr == mFont) return;
520  // сбрасывам флаги
521  mTextOutDate = false;
522 
523  int width = -1;
524  if (mWordWrap)
525  {
526  width = mCoord.width;
527  // обрезать слова нужно по шарине, которую мы реально используем
528  if (mIsAddCursorWidth)
529  width -= 2;
530  }
531 
533  }
534 
536  {
537  EditTextStateInfo* data = _data->castType<EditTextStateInfo>();
538  if (data->getColour() != Colour::Zero) setTextColour(data->getColour());
539  setShiftText(data->getShift());
540  }
541 
543  {
544  if (nullptr == mFont) return;
545  if (!mVisible || mEmptyView) return;
546 
547  bool _update = mRenderItem->getCurrentUpdate();
548  if (_update) mTextOutDate = true;
549 
551 
553 
555 
556  // колличество отрисованных вершин
557  size_t vertex_count = 0;
558 
559  // текущие цвета
560  uint32 colour_current = mCurrentColour;
561  uint32 colour = mCurrentColour;
562  uint32 colour_inverse = mInverseColour;
563 
565 
566  float vertex_z = info.maximumDepth;
567 
568  const VectorLineInfo& data = mTextView.getData();
569 
570  int left = - mViewOffset.left + mCoord.left;
571  int top = - mViewOffset.top + mCoord.top;
572  int width = 0;
573  const int height = mFontHeight;
574 
575  size_t index = 0;
576  for (VectorLineInfo::const_iterator line=data.begin(); line!=data.end(); ++line)
577  {
578  left = line->offset - mViewOffset.left + mCoord.left;
579  for (VectorCharInfo::const_iterator sim=line->simbols.begin(); sim!=line->simbols.end(); ++sim)
580  {
581  if (sim->isColour())
582  {
583  colour = sim->getColour() | (colour & 0xFF000000);
584  colour_inverse = colour ^ 0x00FFFFFF;
585  continue;
586  }
587 
588  // смещение текстуры для фона
589  bool select = !((index >= mEndSelect) || (index < mStartSelect));
590 
591  uint32 back_colour = 0;
592 
593  // выделение символа
594  if (!select || !mInvertSelect)
595  {
596  colour_current = colour;
597  back_colour = colour | 0x00FFFFFF;
598  }
599  else
600  {
601  colour_current = colour_inverse;
602  back_colour = colour_inverse;
603  }
604 
605  bool draw = true;
606 
607  // текущие размеры
608  MyGUI::FloatRect texture_rect = sim->getUVRect();
609  width = sim->getWidth();
610 
611  // конечные размеры
612  int result_left = left;
613  int result_top = top;
614  int result_right = left + width;
615  int result_bottom = top + height;
616 
617  float texture_width = texture_rect.right - texture_rect.left;
618  float texture_height = texture_rect.bottom - texture_rect.top;
619 
620  // символ залазиет влево
621  if (left < mCurrentCoord.left)
622  {
623  // символ вообще не виден
624  if (left + width <= mCurrentCoord.left)
625  {
626  draw = false;
627  }
628  // символ обрезан
629  else
630  {
631  result_left = mCurrentCoord.left;
632  texture_rect.left += (texture_width * (float)(result_left - left) / (float)width);
633  }
634  }
635 
636  // символ залазиет вправо
637  if (left + width > mCurrentCoord.right())
638  {
639  // символ вообще не виден
640  if (left >= mCurrentCoord.right())
641  {
642  draw = false;
643  }
644  // символ обрезан
645  else
646  {
647  result_right = mCurrentCoord.right();
648  texture_rect.right -= (texture_width * (float)((left + width) - result_right) / (float)width);
649  }
650  }
651 
652  // символ залазиет вверх
653  if (top < mCurrentCoord.top)
654  {
655  // символ вообще не виден
656  if (top + height <= mCurrentCoord.top)
657  {
658  draw = false;
659  }
660  // символ обрезан
661  else
662  {
663  result_top = mCurrentCoord.top;
664  texture_rect.top += (texture_height * (float)(result_top - top) / (float)height);
665  }
666  }
667 
668  // символ залазиет вниз
669  if (top + height > mCurrentCoord.bottom())
670  {
671  // символ вообще не виден
672  if (top >= mCurrentCoord.bottom())
673  {
674  draw = false;
675  }
676  // символ обрезан
677  else
678  {
679  result_bottom = mCurrentCoord.bottom();
680  texture_rect.bottom -= (texture_height * (float)((top + height) - result_bottom) / (float)height);
681  }
682  }
683 
684  if (draw)
685  {
686  int pix_left = mCroppedParent->getAbsoluteLeft() - info.leftOffset + result_left;
687  int pix_top = mCroppedParent->getAbsoluteTop() - info.topOffset + (mShiftText ? 1 : 0) + result_top;
688 
689  float real_left = ((info.pixScaleX * (float)(pix_left) + info.hOffset) * 2) - 1;
690  float real_top = - (((info.pixScaleY * (float)(pix_top) + info.vOffset) * 2) - 1);
691  float real_right = ((info.pixScaleX * (float)(pix_left + result_right - result_left) + info.hOffset) * 2) - 1;
692  float real_bottom = - (((info.pixScaleY * (float)(pix_top + result_bottom - result_top) + info.vOffset) * 2) - 1);
693 
694  // если нужно рисуем выделение
695  if (select)
696  {
697  const FloatRect& background_current = back_glyph->uvRect;
698  DrawQuad(_vertex, real_left, real_top, real_right, real_bottom, vertex_z, back_colour,
699  background_current.left, background_current.top, background_current.left, background_current.top, vertex_count);
700  }
701 
702  DrawQuad(_vertex, real_left, real_top, real_right, real_bottom, vertex_z, colour_current,
703  texture_rect.left, texture_rect.top, texture_rect.right, texture_rect.bottom, vertex_count);
704  }
705 
706  left += width;
707  index++;
708  }
709 
710  top += height;
711  index++;
712  }
713 
714  if (mVisibleCursor)
715  {
717  point -= mViewOffset;
718  point += mCoord.point();
719 
720  bool draw = true;
721 
723  MyGUI::FloatRect texture_rect = cursor_glyph->uvRect;
724  left = point.left;
725  top = point.top;
726  width = 2;//cursor_glyph->width;
727 
728  // конечные размеры
729  int result_left = left;
730  int result_top = top;
731  int result_width = width;
732  int result_height = height;
733 
734  // символ залазиет влево
735  if (left < mCurrentCoord.left)
736  {
737  // символ вообще не виден
738  if (left + width <= mCurrentCoord.left)
739  {
740  draw = false;
741  }
742  // символ обрезан
743  else
744  {
745  result_left = mCurrentCoord.left;
746  result_width = width - (mCurrentCoord.left - left);
747 
748  float texture_width = texture_rect.right - texture_rect.left;
749  texture_rect.left = texture_rect.right - (texture_width * (float)result_width / (float)width);
750  }
751  }
752 
753  // символ залазиет вправо
754  if (left + width > mCurrentCoord.right())
755  {
756  // символ вообще не виден
757  if (left >= mCurrentCoord.right())
758  {
759  draw = false;
760  }
761  // символ обрезан
762  else
763  {
764  result_width = mCurrentCoord.right() - left;
765 
766  float texture_width = texture_rect.right - texture_rect.left;
767  texture_rect.right = texture_rect.left + (texture_width * (float)result_width / (float)width);
768  }
769  }
770 
771  // символ залазиет вверх
772  if (top < mCurrentCoord.top)
773  {
774  // символ вообще не виден
775  if (top + height <= mCurrentCoord.top)
776  {
777  draw = false;
778  }
779  // символ обрезан
780  else
781  {
782  result_top = mCurrentCoord.top;
783  result_height = height - (mCurrentCoord.top - top);
784 
785  float texture_height = texture_rect.bottom - texture_rect.top;
786  texture_rect.top = texture_rect.bottom - (texture_height * (float)result_height / (float)height);
787  }
788  }
789 
790  // символ залазиет вниз
791  if (top + height > mCurrentCoord.bottom())
792  {
793  // символ вообще не виден
794  if (top >= mCurrentCoord.bottom())
795  {
796  draw = false;
797  }
798  // символ обрезан
799  else
800  {
801  result_height = mCurrentCoord.bottom() - top;
802 
803  float texture_height = texture_rect.bottom - texture_rect.top;
804  texture_rect.bottom = texture_rect.top + (texture_height * (float)result_height / (float)height);
805  }
806  }
807 
808  if (draw)
809  {
810  int pix_left = mCroppedParent->getAbsoluteLeft() - info.leftOffset + result_left;
811  int pix_top = mCroppedParent->getAbsoluteTop() - info.topOffset + (mShiftText ? 1 : 0) + result_top;
812 
813  float real_left = ((info.pixScaleX * (float)(pix_left) + info.hOffset) * 2) - 1;
814  float real_top = - (((info.pixScaleY * (float)(pix_top) + info.vOffset) * 2) - 1);
815  float real_right = ((info.pixScaleX * (float)(pix_left + result_width) + info.hOffset) * 2) - 1;
816  float real_bottom = - (((info.pixScaleY * (float)(pix_top + result_height) + info.vOffset) * 2) - 1);
817 
818  DrawQuad(_vertex, real_left, real_top, real_right, real_bottom, vertex_z, colour_current | 0x00FFFFFF,
819  texture_rect.left, texture_rect.top, texture_rect.right, texture_rect.bottom, vertex_count);
820  }
821  }
822 
823  // колличество реально отрисованных вершин
824  mRenderItem->setLastVertexCount(vertex_count);
825  }
826 
827  void EditText::setInvertSelected(bool _value)
828  {
829  if (mInvertSelect == _value) return;
830  mInvertSelect = _value;
831  if (nullptr != mNode) mNode->outOfDate(mRenderItem);
832  }
833 
834 } // namespace MyGUI