BsGUIInputSelection.cpp 6.4 KB

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