BsGUIInputBox.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. #include "BsGUIInputBox.h"
  2. #include "BsGUIManager.h"
  3. #include "BsImageSprite.h"
  4. #include "BsGUIWidget.h"
  5. #include "BsGUISkin.h"
  6. #include "BsSpriteTexture.h"
  7. #include "BsTextSprite.h"
  8. #include "BsGUILayoutOptions.h"
  9. #include "BsGUIButtonEvent.h"
  10. #include "BsGUIMouseEvent.h"
  11. #include "BsGUICommandEvent.h"
  12. #include "CmFont.h"
  13. #include "CmTextUtility.h"
  14. #include "CmTexture.h"
  15. #include "CmCursor.h"
  16. using namespace CamelotFramework;
  17. namespace BansheeEngine
  18. {
  19. const String& GUIInputBox::getGUITypeName()
  20. {
  21. static String name = "InputBox";
  22. return name;
  23. }
  24. GUIInputBox::GUIInputBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions, bool multiline)
  25. :GUIElement(parent, style, layoutOptions), mInputCursorSet(false), mDragInProgress(false),
  26. mInputCaret(nullptr), mInputSelection(nullptr), mCaretShown(false), mSelectionShown(false), mIsMultiline(multiline)
  27. {
  28. mImageSprite = cm_new<ImageSprite, PoolAlloc>();
  29. mTextSprite = cm_new<TextSprite, PoolAlloc>();
  30. mInputCaret = cm_new<GUIInputCaret, PoolAlloc>(getTextDesc(), getTextOffset(), mTextOffset);
  31. mInputSelection = cm_new<GUIInputSelection, PoolAlloc>(getTextDesc(), getTextOffset(), mTextOffset);
  32. mImageDesc.texture = mStyle->normal.texture;
  33. if(mImageDesc.texture != nullptr)
  34. {
  35. mImageDesc.width = mImageDesc.texture->getTexture()->getWidth();
  36. mImageDesc.height = mImageDesc.texture->getTexture()->getHeight();
  37. }
  38. mImageDesc.borderLeft = mStyle->border.left;
  39. mImageDesc.borderRight = mStyle->border.right;
  40. mImageDesc.borderTop = mStyle->border.top;
  41. mImageDesc.borderBottom = mStyle->border.bottom;
  42. }
  43. GUIInputBox::~GUIInputBox()
  44. {
  45. cm_delete<PoolAlloc>(mTextSprite);
  46. cm_delete<PoolAlloc>(mImageSprite);
  47. cm_delete<PoolAlloc>(mInputCaret);
  48. cm_delete<PoolAlloc>(mInputSelection);
  49. }
  50. GUIInputBox* GUIInputBox::create(GUIWidget& parent, bool multiline, const GUIElementStyle* style)
  51. {
  52. if(style == nullptr)
  53. {
  54. const GUISkin* skin = parent.getSkin();
  55. style = skin->getStyle(getGUITypeName());
  56. }
  57. return new (cm_alloc<GUIInputBox, PoolAlloc>()) GUIInputBox(parent, style, getDefaultLayoutOptions(style), multiline);
  58. }
  59. GUIInputBox* GUIInputBox::create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, bool multiline, const GUIElementStyle* style)
  60. {
  61. if(style == nullptr)
  62. {
  63. const GUISkin* skin = parent.getSkin();
  64. style = skin->getStyle(getGUITypeName());
  65. }
  66. return new (cm_alloc<GUIInputBox, PoolAlloc>()) GUIInputBox(parent, style, layoutOptions, multiline);
  67. }
  68. UINT32 GUIInputBox::getNumRenderElements() const
  69. {
  70. UINT32 numElements = mImageSprite->getNumRenderElements();
  71. numElements += mTextSprite->getNumRenderElements();
  72. if(mCaretShown && GUIManager::instance().getCaretBlinkState())
  73. numElements += mInputCaret->getSprite()->getNumRenderElements();
  74. if(mSelectionShown)
  75. {
  76. const Vector<ImageSprite*>::type& sprites = mInputSelection->getSprites();
  77. for(auto& selectionSprite : sprites)
  78. {
  79. numElements += selectionSprite->getNumRenderElements();
  80. }
  81. }
  82. return numElements;
  83. }
  84. const HMaterial& GUIInputBox::getMaterial(UINT32 renderElementIdx) const
  85. {
  86. UINT32 localRenderElementIdx;
  87. Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
  88. return sprite->getMaterial(localRenderElementIdx);
  89. }
  90. UINT32 GUIInputBox::getNumQuads(UINT32 renderElementIdx) const
  91. {
  92. UINT32 localRenderElementIdx;
  93. Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
  94. return sprite->getNumQuads(localRenderElementIdx);
  95. }
  96. void GUIInputBox::updateRenderElementsInternal()
  97. {
  98. mImageDesc.width = mWidth;
  99. mImageDesc.height = mHeight;
  100. mImageSprite->update(mImageDesc);
  101. mBounds = mImageSprite->getBounds(mOffset, mClipRect);
  102. TEXT_SPRITE_DESC textDesc = getTextDesc();
  103. mTextSprite->update(textDesc);
  104. if(mCaretShown && GUIManager::instance().getCaretBlinkState())
  105. {
  106. mInputCaret->updateText(textDesc, getTextOffset(), mTextOffset); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
  107. mInputCaret->updateSprite();
  108. }
  109. if(mSelectionShown)
  110. {
  111. mInputSelection->updateText(textDesc, getTextOffset(), mTextOffset); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
  112. mInputSelection->updateSprite();
  113. }
  114. }
  115. Sprite* GUIInputBox::renderElemToSprite(UINT32 renderElemIdx, UINT32& localRenderElemIdx) const
  116. {
  117. UINT32 oldNumElements = 0;
  118. UINT32 newNumElements = oldNumElements + mTextSprite->getNumRenderElements();
  119. if(renderElemIdx < newNumElements)
  120. {
  121. localRenderElemIdx = renderElemIdx - oldNumElements;
  122. return mTextSprite;
  123. }
  124. oldNumElements = newNumElements;
  125. newNumElements += mImageSprite->getNumRenderElements();
  126. if(renderElemIdx < newNumElements)
  127. {
  128. localRenderElemIdx = renderElemIdx - oldNumElements;
  129. return mImageSprite;
  130. }
  131. if(mCaretShown && GUIManager::instance().getCaretBlinkState())
  132. {
  133. oldNumElements = newNumElements;
  134. newNumElements += mInputCaret->getSprite()->getNumRenderElements();
  135. if(renderElemIdx < newNumElements)
  136. {
  137. localRenderElemIdx = renderElemIdx - oldNumElements;
  138. return mInputCaret->getSprite();
  139. }
  140. }
  141. if(mSelectionShown)
  142. {
  143. const Vector<ImageSprite*>::type& sprites = mInputSelection->getSprites();
  144. for(auto& selectionSprite : sprites)
  145. {
  146. oldNumElements = newNumElements;
  147. newNumElements += selectionSprite->getNumRenderElements();
  148. if(renderElemIdx < newNumElements)
  149. {
  150. localRenderElemIdx = renderElemIdx - oldNumElements;
  151. return selectionSprite;
  152. }
  153. }
  154. }
  155. localRenderElemIdx = renderElemIdx;
  156. return nullptr;
  157. }
  158. Int2 GUIInputBox::renderElemToOffset(UINT32 renderElemIdx) const
  159. {
  160. UINT32 oldNumElements = 0;
  161. UINT32 newNumElements = oldNumElements + mTextSprite->getNumRenderElements();
  162. if(renderElemIdx < newNumElements)
  163. return getTextOffset();
  164. oldNumElements = newNumElements;
  165. newNumElements += mImageSprite->getNumRenderElements();
  166. if(renderElemIdx < newNumElements)
  167. return mOffset;
  168. if(mCaretShown && GUIManager::instance().getCaretBlinkState())
  169. {
  170. oldNumElements = newNumElements;
  171. newNumElements += mInputCaret->getSprite()->getNumRenderElements();
  172. if(renderElemIdx < newNumElements)
  173. return mInputCaret->getSpriteOffset();
  174. }
  175. if(mSelectionShown)
  176. {
  177. UINT32 spriteIdx = 0;
  178. const Vector<ImageSprite*>::type& sprites = mInputSelection->getSprites();
  179. for(auto& selectionSprite : sprites)
  180. {
  181. oldNumElements = newNumElements;
  182. newNumElements += selectionSprite->getNumRenderElements();
  183. if(renderElemIdx < newNumElements)
  184. return mInputSelection->getSelectionSpriteOffset(spriteIdx);
  185. spriteIdx++;
  186. }
  187. }
  188. return Int2();
  189. }
  190. Rect GUIInputBox::renderElemToClipRect(UINT32 renderElemIdx) const
  191. {
  192. UINT32 oldNumElements = 0;
  193. UINT32 newNumElements = oldNumElements + mTextSprite->getNumRenderElements();
  194. if(renderElemIdx < newNumElements)
  195. return getTextClipRect();
  196. oldNumElements = newNumElements;
  197. newNumElements += mImageSprite->getNumRenderElements();
  198. if(renderElemIdx < newNumElements)
  199. return mClipRect;
  200. if(mCaretShown && GUIManager::instance().getCaretBlinkState())
  201. {
  202. oldNumElements = newNumElements;
  203. newNumElements += mInputCaret->getSprite()->getNumRenderElements();
  204. if(renderElemIdx < newNumElements)
  205. return mInputCaret->getSpriteClipRect();
  206. }
  207. if(mSelectionShown)
  208. {
  209. UINT32 spriteIdx = 0;
  210. const Vector<ImageSprite*>::type& sprites = mInputSelection->getSprites();
  211. for(auto& selectionSprite : sprites)
  212. {
  213. oldNumElements = newNumElements;
  214. newNumElements += selectionSprite->getNumRenderElements();
  215. if(renderElemIdx < newNumElements)
  216. return mInputSelection->getSelectionSpriteClipRect(spriteIdx);
  217. spriteIdx++;
  218. }
  219. }
  220. return Rect();
  221. }
  222. UINT32 GUIInputBox::_getOptimalWidth() const
  223. {
  224. if(mImageDesc.texture != nullptr)
  225. {
  226. return mImageDesc.texture->getTexture()->getWidth();
  227. }
  228. return 0;
  229. }
  230. UINT32 GUIInputBox::_getOptimalHeight() const
  231. {
  232. if(mImageDesc.texture != nullptr)
  233. {
  234. return mImageDesc.texture->getTexture()->getHeight();
  235. }
  236. return 0;
  237. }
  238. UINT32 GUIInputBox::_getRenderElementDepth(UINT32 renderElementIdx) const
  239. {
  240. UINT32 localRenderElementIdx;
  241. Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
  242. if(sprite == mImageSprite)
  243. return _getDepth();
  244. else if(sprite == mTextSprite)
  245. return _getDepth() - 2;
  246. else if(sprite == mInputCaret->getSprite())
  247. return _getDepth() - 3;
  248. else // Selection sprites
  249. return _getDepth() - 1;
  250. }
  251. void GUIInputBox::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads,
  252. UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
  253. {
  254. UINT32 localRenderElementIdx;
  255. Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
  256. Int2 offset = renderElemToOffset(renderElementIdx);
  257. Rect clipRect = renderElemToClipRect(renderElementIdx);
  258. sprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, localRenderElementIdx, offset, clipRect);
  259. }
  260. bool GUIInputBox::mouseEvent(const GUIMouseEvent& ev)
  261. {
  262. if(ev.getType() == GUIMouseEventType::MouseOver)
  263. {
  264. mImageDesc.texture = mStyle->hover.texture;
  265. markAsDirty();
  266. if(!mInputCursorSet)
  267. {
  268. Cursor::setCursor(CursorType::IBeam);
  269. mInputCursorSet = true;
  270. }
  271. return true;
  272. }
  273. else if(ev.getType() == GUIMouseEventType::MouseOut)
  274. {
  275. mImageDesc.texture = mStyle->normal.texture;
  276. markAsDirty();
  277. if(!mDragInProgress && mInputCursorSet)
  278. {
  279. Cursor::setCursor(CursorType::Arrow);
  280. mInputCursorSet = false;
  281. }
  282. return true;
  283. }
  284. else if(ev.getType() == GUIMouseEventType::MouseDown)
  285. {
  286. mImageDesc.texture = mStyle->active.texture;
  287. showCaret();
  288. if(mText.size() > 0)
  289. mInputCaret->moveCaretToPos(ev.getPosition());
  290. else
  291. mInputCaret->moveCaretToStart();
  292. scrollTextToCaret();
  293. clearSelection();
  294. markAsDirty();
  295. return true;
  296. }
  297. else if(ev.getType() == GUIMouseEventType::MouseUp)
  298. {
  299. mImageDesc.texture = mStyle->hover.texture;
  300. markAsDirty();
  301. return true;
  302. }
  303. else if(ev.getType() == GUIMouseEventType::MouseDragStart)
  304. {
  305. mDragInProgress = true;
  306. UINT32 caretPos = mInputCaret->getCaretPos();
  307. showSelection(caretPos);
  308. mInputSelection->selectionDragStart(caretPos);
  309. return true;
  310. }
  311. else if(ev.getType() == GUIMouseEventType::MouseDragEnd)
  312. {
  313. mDragInProgress = false;
  314. if(ev.getMouseOverElement() != this && mInputCursorSet)
  315. {
  316. Cursor::setCursor(CursorType::Arrow);
  317. mInputCursorSet = false;
  318. }
  319. mInputSelection->selectionDragEnd();
  320. return true;
  321. }
  322. else if(ev.getType() == GUIMouseEventType::MouseDrag)
  323. {
  324. Rect bounds = getTextBounds();
  325. if(mText.size() > 0)
  326. mInputCaret->moveCaretToPos(ev.getPosition());
  327. else
  328. mInputCaret->moveCaretToStart();
  329. mInputSelection->selectionDragUpdate(mInputCaret->getCaretPos());
  330. scrollTextToCaret();
  331. markAsDirty();
  332. return true;
  333. }
  334. return false;
  335. }
  336. bool GUIInputBox::keyEvent(const GUIKeyEvent& ev)
  337. {
  338. if(ev.getType() == GUIKeyEventType::KeyDown)
  339. {
  340. if(ev.getKey() == BC_BACK)
  341. {
  342. if(mText.size() > 0)
  343. {
  344. if(mSelectionShown)
  345. {
  346. deleteSelectedText();
  347. }
  348. else
  349. {
  350. UINT32 charIdx = mInputCaret->getCharIdxAtCaretPos() - 1;
  351. if(charIdx < (UINT32)mText.size())
  352. {
  353. eraseChar(charIdx);
  354. if(charIdx > 0)
  355. charIdx--;
  356. mInputCaret->moveCaretToChar(charIdx, CARET_AFTER);
  357. scrollTextToCaret();
  358. }
  359. }
  360. markAsDirty();
  361. }
  362. return true;
  363. }
  364. if(ev.getKey() == BC_DELETE)
  365. {
  366. if(mText.size() > 0)
  367. {
  368. if(mSelectionShown)
  369. {
  370. deleteSelectedText();
  371. }
  372. else
  373. {
  374. UINT32 charIdx = mInputCaret->getCharIdxAtCaretPos();
  375. if(charIdx < (UINT32)mText.size())
  376. {
  377. eraseChar(charIdx);
  378. if(charIdx > 0)
  379. charIdx--;
  380. mInputCaret->moveCaretToChar(charIdx, CARET_AFTER);
  381. scrollTextToCaret();
  382. }
  383. }
  384. markAsDirty();
  385. }
  386. return true;
  387. }
  388. if(ev.getKey() == BC_LEFT)
  389. {
  390. if(ev.isShiftDown())
  391. {
  392. //bool caretMovedDueToNewline = false;
  393. //if(!mSelectionShown)
  394. //{
  395. // if(isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Right)))
  396. // {
  397. // mInputCaret->moveCaretLeft();
  398. // caretMovedDueToNewline = true;
  399. // }
  400. // showSelection(mInputCaret->getCaretPos(), SelectionDir::Left);
  401. //}
  402. //moveSelectionLeft(caretMovedDueToNewline);
  403. //scrollTextToCaret();
  404. //markAsDirty();
  405. //return true;
  406. }
  407. else
  408. {
  409. clearSelection();
  410. mInputCaret->moveCaretLeft();
  411. scrollTextToCaret();
  412. markAsDirty();
  413. return true;
  414. }
  415. }
  416. if(ev.getKey() == BC_RIGHT)
  417. {
  418. if(ev.isShiftDown())
  419. {
  420. //bool caretMovedDueToNewline = false;
  421. //if(!mSelectionShown)
  422. //{
  423. // if(isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Left)))
  424. // {
  425. // mInputCaret->moveCaretRight();
  426. // caretMovedDueToNewline = true;
  427. // }
  428. // showSelection(mInputCaret->getCaretPos(), SelectionDir::Left);
  429. //}
  430. //
  431. //moveSelectionRight(caretMovedDueToNewline);
  432. //scrollTextToCaret();
  433. //markAsDirty();
  434. //return true;
  435. }
  436. else
  437. {
  438. clearSelection();
  439. mInputCaret->moveCaretRight();
  440. scrollTextToCaret();
  441. markAsDirty();
  442. return true;
  443. }
  444. }
  445. if(ev.getKey() == BC_UP)
  446. {
  447. if(ev.isShiftDown())
  448. {
  449. if(!mSelectionShown)
  450. {
  451. if(mInputCaret->isNewlineBefore(mInputCaret->getCaretPos()))
  452. mInputCaret->moveCaretLeft();
  453. showSelection(mInputCaret->getCaretPos());
  454. }
  455. }
  456. else
  457. {
  458. clearSelection();
  459. }
  460. mInputCaret->moveCaretUp();
  461. scrollTextToCaret();
  462. if(ev.isShiftDown())
  463. {
  464. mInputSelection->moveSelectionToCaret(mInputCaret->getCaretPos());
  465. }
  466. markAsDirty();
  467. return true;
  468. }
  469. if(ev.getKey() == BC_DOWN)
  470. {
  471. if(ev.isShiftDown())
  472. {
  473. if(!mSelectionShown)
  474. {
  475. if(mInputCaret->isNewlineAfter(mInputCaret->getCaretPos()))
  476. mInputCaret->moveCaretRight();
  477. showSelection(mInputCaret->getCaretPos());
  478. }
  479. }
  480. else
  481. {
  482. clearSelection();
  483. }
  484. mInputCaret->moveCaretDown();
  485. scrollTextToCaret();
  486. if(ev.isShiftDown())
  487. {
  488. mInputSelection->moveSelectionToCaret(mInputCaret->getCaretPos());
  489. }
  490. markAsDirty();
  491. return true;
  492. }
  493. if(ev.getKey() == BC_RETURN)
  494. {
  495. if(mIsMultiline)
  496. {
  497. if(mSelectionShown)
  498. deleteSelectedText();
  499. insertChar(mInputCaret->getCharIdxAtCaretPos(), '\n');
  500. mInputCaret->moveCaretRight();
  501. scrollTextToCaret();
  502. markAsDirty();
  503. return true;
  504. }
  505. }
  506. if(ev.getKey() == BC_A && ev.isCtrlDown())
  507. {
  508. showSelection(0);
  509. mInputSelection->selectAll();
  510. markAsDirty();
  511. return true;
  512. }
  513. }
  514. else if(ev.getType() == GUIKeyEventType::TextInput)
  515. {
  516. if(mSelectionShown)
  517. deleteSelectedText();
  518. UINT32 charIdx = mInputCaret->getCharIdxAtCaretPos();
  519. insertChar(charIdx, ev.getInputChar());
  520. mInputCaret->moveCaretToChar(charIdx, CARET_AFTER);
  521. scrollTextToCaret();
  522. markAsDirty();
  523. return true;
  524. }
  525. return false;
  526. }
  527. bool GUIInputBox::commandEvent(const GUICommandEvent& ev)
  528. {
  529. if(ev.getType() == GUICommandEventType::Redraw)
  530. {
  531. markAsDirty();
  532. return true;
  533. }
  534. return false;
  535. }
  536. void GUIInputBox::showCaret()
  537. {
  538. mCaretShown = true;
  539. markAsDirty();
  540. }
  541. void GUIInputBox::hideCaret()
  542. {
  543. mCaretShown = false;
  544. markAsDirty();
  545. }
  546. void GUIInputBox::showSelection(CM::UINT32 anchorCaretPos)
  547. {
  548. mInputSelection->showSelection(anchorCaretPos);
  549. mSelectionShown = true;
  550. markAsDirty();
  551. }
  552. void GUIInputBox::clearSelection()
  553. {
  554. mInputSelection->clearSelection();
  555. mSelectionShown = false;
  556. markAsDirty();
  557. }
  558. void GUIInputBox::scrollTextToCaret()
  559. {
  560. TEXT_SPRITE_DESC textDesc = getTextDesc();
  561. Int2 textOffset = getTextOffset();
  562. Int2 caretPos = mInputCaret->getCaretPosition(textOffset);
  563. UINT32 caretHeight = mInputCaret->getCaretHeight();
  564. UINT32 caretWidth = 1;
  565. INT32 caretRight = caretPos.x + (INT32)caretWidth;
  566. INT32 caretBottom = caretPos.y + (INT32)caretHeight;
  567. INT32 left = textOffset.x - mTextOffset.x;
  568. // Include caret width here because we don't want to scroll if just the caret is outside the bounds
  569. // (Possible if the text width is exactly the maximum width)
  570. INT32 right = left + (INT32)textDesc.width + caretWidth;
  571. INT32 top = textOffset.y - mTextOffset.y;
  572. INT32 bottom = top + (INT32)textDesc.height;
  573. Int2 offset;
  574. if(caretPos.x < left)
  575. {
  576. offset.x = left - caretPos.x;
  577. }
  578. else if(caretRight > right)
  579. {
  580. offset.x = -(caretRight - right);
  581. }
  582. if(caretPos.y < top)
  583. {
  584. offset.y = top - caretPos.y;
  585. }
  586. else if(caretBottom > bottom)
  587. {
  588. offset.y = -(caretBottom - bottom);
  589. }
  590. mTextOffset += offset;
  591. Int2 newOffset = getTextOffset();
  592. mInputCaret->updateText(textDesc, newOffset, mTextOffset);
  593. mInputSelection->updateText(textDesc, newOffset, mTextOffset);
  594. markAsDirty();
  595. }
  596. void GUIInputBox::insertChar(CM::UINT32 charIdx, CM::UINT32 charCode)
  597. {
  598. mText.insert(mText.begin() + charIdx, charCode);
  599. TEXT_SPRITE_DESC textDesc = getTextDesc();
  600. Int2 offset = getTextOffset();
  601. mInputCaret->updateText(textDesc, offset, mTextOffset);
  602. mInputSelection->updateText(textDesc, offset, mTextOffset);
  603. }
  604. void GUIInputBox::eraseChar(CM::UINT32 charIdx)
  605. {
  606. mText.erase(charIdx, 1);
  607. TEXT_SPRITE_DESC textDesc = getTextDesc();
  608. Int2 offset = getTextOffset();
  609. mInputCaret->updateText(textDesc, offset, mTextOffset);
  610. mInputSelection->updateText(textDesc, offset, mTextOffset);
  611. }
  612. void GUIInputBox::deleteSelectedText()
  613. {
  614. UINT32 selStart = mInputSelection->getSelectionStart();
  615. mText.erase(mText.begin() + selStart, mText.begin() + mInputSelection->getSelectionEnd());
  616. TEXT_SPRITE_DESC textDesc = getTextDesc();
  617. Int2 offset = getTextOffset();
  618. mInputCaret->updateText(textDesc, offset, mTextOffset);
  619. mInputSelection->updateText(textDesc, offset, mTextOffset);
  620. if(selStart > 0)
  621. {
  622. UINT32 newCaretPos = selStart - 1;
  623. mInputCaret->moveCaretToChar(newCaretPos, CARET_AFTER);
  624. }
  625. else
  626. {
  627. mInputCaret->moveCaretToChar(0, CARET_BEFORE);
  628. }
  629. scrollTextToCaret();
  630. clearSelection();
  631. }
  632. //void GUIInputBox::moveSelectionLeft(bool skipNewline)
  633. //{
  634. // SelectionDir newlineTestSelectionDir;
  635. // if(mSelectionAnchor == mSelectionEnd)
  636. // newlineTestSelectionDir = SelectionDir::Left;
  637. // else
  638. // newlineTestSelectionDir = SelectionDir::Right;
  639. // if(mInputCaret->getCaretPos() > 0)
  640. // {
  641. // mInputCaret->moveCaretLeft();
  642. // if(!skipNewline) // Move one more if we moved to a new line (we can't select newline char so we skip it)
  643. // {
  644. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)) && mInputCaret->getCaretPos() > 0)
  645. // {
  646. // mInputCaret->moveCaretLeft();
  647. // // Reverse caret movement if previous char was a newline, and this one is as well.
  648. // // Otherwise we skip an entire line which is not what we want.
  649. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)))
  650. // mInputCaret->moveCaretRight();
  651. // }
  652. // }
  653. // else
  654. // {
  655. // // Reverse caret movement if previous char was a newline, and this one is as well
  656. // // so we don't skip a line
  657. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)))
  658. // mInputCaret->moveCaretRight();
  659. // }
  660. // }
  661. // UINT32 charIdx = caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Left);
  662. //
  663. // if(mSelectionAnchor == mSelectionEnd)
  664. // mSelectionStart = std::min(mSelectionEnd, charIdx);
  665. // else
  666. // mSelectionEnd = std::max(mSelectionStart, charIdx);
  667. // if(mSelectionStart == mSelectionEnd)
  668. // clearSelection();
  669. //}
  670. //void GUIInputBox::moveSelectionRight(bool skipNewline)
  671. //{
  672. // SelectionDir newlineTestSelectionDir;
  673. // if(mSelectionAnchor == mSelectionStart)
  674. // newlineTestSelectionDir = SelectionDir::Right;
  675. // else
  676. // newlineTestSelectionDir = SelectionDir::Left;
  677. // UINT32 maxCaretPos = mInputCaret->getMaxCaretPos();
  678. // if(mInputCaret->getCaretPos() < maxCaretPos)
  679. // {
  680. // mInputCaret->moveCaretRight();
  681. // if(!skipNewline) // Move one more if we moved to a new line (we can't select newline char so we skip it)
  682. // {
  683. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)) && mInputCaret->getCaretPos() < maxCaretPos)
  684. // {
  685. // mInputCaret->moveCaretRight();
  686. // // Reverse caret movement if previous char was a newline, and this one is as well.
  687. // // Otherwise we skip an entire line which is not what we want.
  688. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)))
  689. // mInputCaret->moveCaretLeft();
  690. // }
  691. // }
  692. // else
  693. // {
  694. // // Reverse caret movement if previous char was a newline, and this one is as well.
  695. // // Otherwise we skip an entire line which is not what we want.
  696. // if (isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), newlineTestSelectionDir)))
  697. // mInputCaret->moveCaretLeft();
  698. // }
  699. // }
  700. // UINT32 charIdx = caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Left);
  701. // if(mSelectionAnchor == mSelectionStart)
  702. // mSelectionEnd = std::max(mSelectionStart, charIdx);
  703. // else
  704. // mSelectionStart = std::min(mSelectionEnd, charIdx);
  705. // if(mSelectionStart == mSelectionEnd)
  706. // clearSelection();
  707. //}
  708. CM::Int2 GUIInputBox::getTextOffset() const
  709. {
  710. Rect textBounds = getTextBounds();
  711. return Int2(textBounds.x, textBounds.y) + mTextOffset;
  712. }
  713. CM::Rect GUIInputBox::getTextClipRect() const
  714. {
  715. Rect textBounds = getTextBounds();
  716. return Rect(-mTextOffset.x, -mTextOffset.y, textBounds.width, textBounds.height);
  717. }
  718. CM::Rect GUIInputBox::getTextBounds() const
  719. {
  720. Rect textBounds = mBounds;
  721. textBounds.x += mStyle->margins.left + mStyle->contentOffset.left;
  722. textBounds.y += mStyle->margins.top + mStyle->contentOffset.top;
  723. textBounds.width = (UINT32)std::max(0, (INT32)textBounds.width -
  724. (INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
  725. textBounds.height = (UINT32)std::max(0, (INT32)textBounds.height -
  726. (INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
  727. return textBounds;
  728. }
  729. TEXT_SPRITE_DESC GUIInputBox::getTextDesc() const
  730. {
  731. TEXT_SPRITE_DESC textDesc;
  732. textDesc.text = mText;
  733. textDesc.font = mStyle->font;
  734. textDesc.fontSize = mStyle->fontSize;
  735. Rect textBounds = getTextBounds();
  736. textDesc.width = textBounds.width;
  737. textDesc.height = textBounds.height;
  738. textDesc.horzAlign = mStyle->textHorzAlign;
  739. textDesc.vertAlign = mStyle->textVertAlign;
  740. textDesc.wordWrap = mIsMultiline;
  741. return textDesc;
  742. }
  743. void GUIInputBox::_setFocus(bool focus)
  744. {
  745. if(focus)
  746. {
  747. mImageDesc.texture = mStyle->focused.texture;
  748. markAsDirty();
  749. }
  750. else
  751. {
  752. mImageDesc.texture = mStyle->normal.texture;
  753. hideCaret();
  754. clearSelection();
  755. markAsDirty();
  756. }
  757. }
  758. }