BsGUIInputSelection.cpp 6.8 KB

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