BsGUIInputSelection.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "BsGUIInputSelection.h"
  2. #include "BsSpriteTexture.h"
  3. #include "BsImageSprite.h"
  4. #include "BsGUIElement.h"
  5. #include "BsGUIManager.h"
  6. using namespace CamelotFramework;
  7. namespace BansheeEngine
  8. {
  9. GUIInputSelection::GUIInputSelection()
  10. :mSelectionStart(0), mSelectionEnd(0), mSelectionAnchor(0), mSelectionDragAnchor(0)
  11. { }
  12. GUIInputSelection::~GUIInputSelection()
  13. {
  14. for(auto& sprite : mSprites)
  15. cm_delete<PoolAlloc>(sprite);
  16. }
  17. void GUIInputSelection::updateSprite()
  18. {
  19. mSelectionRects = getSelectionRects();
  20. INT32 diff = (INT32)(mSprites.size() - mSelectionRects.size());
  21. if(diff > 0)
  22. {
  23. for(UINT32 i = (UINT32)mSelectionRects.size(); i < (UINT32)mSprites.size(); i++)
  24. cm_delete(mSprites[i]);
  25. mSprites.erase(mSprites.begin() + mSelectionRects.size(), mSprites.end());
  26. }
  27. else if(diff < 0)
  28. {
  29. for(INT32 i = diff; i < 0; i++)
  30. {
  31. ImageSprite* newSprite = cm_new<ImageSprite>();
  32. mSprites.push_back(newSprite);
  33. }
  34. }
  35. UINT32 idx = 0;
  36. for(auto& sprite : mSprites)
  37. {
  38. IMAGE_SPRITE_DESC desc;
  39. desc.width = mSelectionRects[idx].width;
  40. desc.height = mSelectionRects[idx].height;
  41. desc.texture = GUIManager::instance().getTextSelectionTexture().getInternalPtr();
  42. sprite->update(desc);
  43. idx++;
  44. }
  45. }
  46. Vector2I GUIInputSelection::getSelectionSpriteOffset(UINT32 spriteIdx) const
  47. {
  48. return Vector2I(mSelectionRects[spriteIdx].x, mSelectionRects[spriteIdx].y) + getTextOffset();
  49. }
  50. RectI GUIInputSelection::getSelectionSpriteClipRect(UINT32 spriteIdx, const CM::RectI& parentClipRect) const
  51. {
  52. Vector2I selectionOffset(mSelectionRects[spriteIdx].x, mSelectionRects[spriteIdx].y);
  53. Vector2I clipOffset = selectionOffset + mElement->_getTextInputOffset();
  54. RectI clipRect(-clipOffset.x, -clipOffset.y, mTextDesc.width, mTextDesc.height);
  55. RectI localParentCliprect = parentClipRect;
  56. // Move parent rect to our space
  57. localParentCliprect.x += mElement->_getTextInputOffset().x + clipRect.x;
  58. localParentCliprect.y += mElement->_getTextInputOffset().y + clipRect.y;
  59. // Clip our rectangle so its not larger then the parent
  60. clipRect.clip(localParentCliprect);
  61. // Increase clip size by 1, so we can fit the caret in case it is fully at the end of the text
  62. clipRect.width += 1;
  63. return clipRect;
  64. }
  65. Vector<RectI>::type GUIInputSelection::getSelectionRects() const
  66. {
  67. Vector<RectI>::type selectionRects;
  68. if(mSelectionStart == mSelectionEnd)
  69. return selectionRects;
  70. UINT32 startLine = getLineForChar(mSelectionStart);
  71. UINT32 endLine = startLine;
  72. if(mSelectionEnd > 0)
  73. endLine = getLineForChar(mSelectionEnd - 1, true);
  74. {
  75. const GUIInputLineDesc& lineDesc = getLineDesc(startLine);
  76. UINT32 startCharIdx = mSelectionStart;
  77. UINT32 endCharIdx = mSelectionEnd - 1;
  78. if(startLine != endLine)
  79. {
  80. endCharIdx = lineDesc.getEndChar(false);
  81. if(endCharIdx > 0)
  82. endCharIdx = endCharIdx - 1;
  83. }
  84. if(!isNewlineChar(startCharIdx) && !isNewlineChar(endCharIdx))
  85. {
  86. RectI startChar = getLocalCharRect(startCharIdx);
  87. RectI endChar = getLocalCharRect(endCharIdx);
  88. RectI selectionRect;
  89. selectionRect.x = startChar.x;
  90. selectionRect.y = lineDesc.getLineYStart();
  91. selectionRect.height = lineDesc.getLineHeight();
  92. selectionRect.width = (endChar.x + endChar.width) - startChar.x;
  93. selectionRects.push_back(selectionRect);
  94. }
  95. }
  96. for(UINT32 i = startLine + 1; i < endLine; i++)
  97. {
  98. const GUIInputLineDesc& lineDesc = getLineDesc(i);
  99. if(lineDesc.getStartChar() == lineDesc.getEndChar() || isNewlineChar(lineDesc.getStartChar()))
  100. continue;
  101. UINT32 endCharIdx = lineDesc.getEndChar(false);
  102. if(endCharIdx > 0)
  103. endCharIdx = endCharIdx - 1;
  104. RectI startChar = getLocalCharRect(lineDesc.getStartChar());
  105. RectI endChar = getLocalCharRect(endCharIdx);
  106. RectI selectionRect;
  107. selectionRect.x = startChar.x;
  108. selectionRect.y = lineDesc.getLineYStart();
  109. selectionRect.height = lineDesc.getLineHeight();
  110. selectionRect.width = (endChar.x + endChar.width) - startChar.x;
  111. selectionRects.push_back(selectionRect);
  112. }
  113. if(startLine != endLine)
  114. {
  115. const GUIInputLineDesc& lineDesc = getLineDesc(endLine);
  116. if(lineDesc.getStartChar() != lineDesc.getEndChar() && !isNewlineChar(lineDesc.getStartChar()))
  117. {
  118. UINT32 endCharIdx = mSelectionEnd - 1;
  119. if(!isNewlineChar(endCharIdx))
  120. {
  121. RectI startChar = getLocalCharRect(lineDesc.getStartChar());
  122. RectI endChar = getLocalCharRect(endCharIdx);
  123. RectI selectionRect;
  124. selectionRect.x = startChar.x;
  125. selectionRect.y = lineDesc.getLineYStart();
  126. selectionRect.height = lineDesc.getLineHeight();
  127. selectionRect.width = (endChar.x + endChar.width) - startChar.x;
  128. selectionRects.push_back(selectionRect);
  129. }
  130. }
  131. }
  132. return selectionRects;
  133. }
  134. void GUIInputSelection::showSelection(CM::UINT32 anchorCaretPos)
  135. {
  136. UINT32 charIdx = getCharIdxAtInputIdx(anchorCaretPos);
  137. mSelectionStart = charIdx;
  138. mSelectionEnd = charIdx;
  139. mSelectionAnchor = charIdx;
  140. }
  141. void GUIInputSelection::clearSelection()
  142. {
  143. for(auto& sprite : mSprites)
  144. cm_delete(sprite);
  145. mSprites.clear();
  146. }
  147. void GUIInputSelection::selectionDragStart(UINT32 caretPos)
  148. {
  149. clearSelection();
  150. showSelection(caretPos);
  151. mSelectionDragAnchor = caretPos;
  152. }
  153. void GUIInputSelection::selectionDragUpdate(UINT32 caretPos)
  154. {
  155. if(caretPos < mSelectionDragAnchor)
  156. {
  157. mSelectionStart = getCharIdxAtInputIdx(caretPos);
  158. mSelectionEnd = getCharIdxAtInputIdx(mSelectionDragAnchor);
  159. mSelectionAnchor = mSelectionStart;
  160. }
  161. if(caretPos > mSelectionDragAnchor)
  162. {
  163. mSelectionStart = getCharIdxAtInputIdx(mSelectionDragAnchor);
  164. mSelectionEnd = getCharIdxAtInputIdx(caretPos);
  165. mSelectionAnchor = mSelectionEnd;
  166. }
  167. if(caretPos == mSelectionDragAnchor)
  168. {
  169. mSelectionStart = mSelectionAnchor;
  170. mSelectionEnd = mSelectionAnchor;
  171. }
  172. }
  173. void GUIInputSelection::selectionDragEnd()
  174. {
  175. if(isSelectionEmpty())
  176. clearSelection();
  177. }
  178. void GUIInputSelection::moveSelectionToCaret(UINT32 caretPos)
  179. {
  180. UINT32 charIdx = getCharIdxAtInputIdx(caretPos);
  181. if(charIdx > mSelectionAnchor)
  182. {
  183. mSelectionStart = mSelectionAnchor;
  184. mSelectionEnd = charIdx;
  185. }
  186. else
  187. {
  188. mSelectionStart = charIdx;
  189. mSelectionEnd = mSelectionAnchor;
  190. }
  191. if(mSelectionStart == mSelectionEnd)
  192. clearSelection();
  193. }
  194. void GUIInputSelection::selectAll()
  195. {
  196. mSelectionStart = 0;
  197. mSelectionEnd = (UINT32)mTextDesc.text.size();
  198. }
  199. bool GUIInputSelection::isSelectionEmpty() const
  200. {
  201. return mSelectionStart == mSelectionEnd;
  202. }
  203. }