BsGUIInputSelection.cpp 6.6 KB

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