lllineeditor.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /**
  2. * @file lllineeditor.h
  3. * @brief Text editor widget to let users enter/edit a single line.
  4. *
  5. * Features:
  6. * Text entry of a single line (text, delete, left and right arrow, insert, return).
  7. * Callbacks either on every keystroke or just on the return key.
  8. * Focus (allow multiple text entry widgets)
  9. * Clipboard (cut, copy, and paste)
  10. * Horizontal scrolling to allow strings longer than widget size allows
  11. * Pre-validation (limit which keys can be used)
  12. * Optional line history so previous entries can be recalled by CTRL UP/DOWN
  13. *
  14. * $LicenseInfo:firstyear=2001&license=viewergpl$
  15. *
  16. * Copyright (c) 2001-2009, Linden Research, Inc.
  17. *
  18. * Second Life Viewer Source Code
  19. * The source code in this file ("Source Code") is provided by Linden Lab
  20. * to you under the terms of the GNU General Public License, version 2.0
  21. * ("GPL"), unless you have obtained a separate licensing agreement
  22. * ("Other License"), formally executed by you and Linden Lab. Terms of
  23. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  24. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  25. *
  26. * There are special exceptions to the terms and conditions of the GPL as
  27. * it is applied to this Source Code. View the full text of the exception
  28. * in the file doc/FLOSS-exception.txt in this software distribution, or
  29. * online at
  30. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  31. *
  32. * By copying, modifying or distributing this software, you acknowledge
  33. * that you have read and understood your obligations described above,
  34. * and agree to abide by those obligations.
  35. *
  36. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  37. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  38. * COMPLETENESS OR PERFORMANCE.
  39. * $/LicenseInfo$
  40. */
  41. #ifndef LL_LLLINEEDITOR_H
  42. #define LL_LLLINEEDITOR_H
  43. #include "llcolor4.h"
  44. #include "lleditmenuhandler.h"
  45. #include "llframetimer.h"
  46. #include "llpreeditor.h"
  47. #include "lluictrl.h"
  48. #include "llviewborder.h"
  49. class LLButton;
  50. class LLLineEditorRollback;
  51. class LLFontGL;
  52. class LLMenuItemCallGL;
  53. typedef bool (*LLLinePrevalidateFunc)(const LLWString& wstr);
  54. class LLLineEditor : public LLUICtrl, public LLEditMenuHandler,
  55. protected LLPreeditor
  56. {
  57. protected:
  58. LOG_CLASS(LLLineEditor);
  59. public:
  60. LLLineEditor(const std::string& name, const LLRect& rect,
  61. const std::string& default_text = LLStringUtil::null,
  62. const LLFontGL* glfont = NULL, S32 max_length_bytes = 254,
  63. void (*commit_callback)(LLUICtrl*, void*) = NULL,
  64. void (*keystroke_callback)(LLLineEditor*, void*) = NULL,
  65. void (*focus_lost_callback)(LLFocusableElement*,
  66. void*) = NULL,
  67. void* userdata = NULL,
  68. LLLinePrevalidateFunc prevalidate_func = NULL,
  69. LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
  70. LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE,
  71. S32 border_thickness = 1);
  72. ~LLLineEditor() override;
  73. const std::string& getTag() const override;
  74. LLXMLNodePtr getXML(bool save_children = true) const override;
  75. void setColorParameters(LLXMLNodePtr nodep);
  76. static LLView* fromXML(LLXMLNodePtr nodep, LLView* parentp,
  77. LLUICtrlFactory*);
  78. static void cleanupLineEditor();
  79. // Mouse handler overrides
  80. bool handleMouseDown(S32 x, S32 y, MASK mask) override;
  81. bool handleMouseUp(S32 x, S32 y, MASK mask) override;
  82. bool handleRightMouseDown(S32 x, S32 y, MASK mask) override;
  83. bool handleHover(S32 x, S32 y, MASK mask) override;
  84. bool handleDoubleClick(S32 x,S32 y,MASK mask) override;
  85. bool handleMiddleMouseDown(S32 x,S32 y,MASK mask) override;
  86. bool handleKeyHere(KEY key, MASK mask) override;
  87. bool handleUnicodeCharHere(llwchar uni_char) override;
  88. void onMouseCaptureLost() override;
  89. // Returns true if user changed value at all
  90. LL_INLINE virtual bool isSpellDirty() const { return mText.getString() != mPrevSpelledText; }
  91. // Clear dirty state
  92. LL_INLINE virtual void resetSpellDirty() { mPrevSpelledText = mText.getString(); }
  93. struct SpellMenuBind
  94. {
  95. LLLineEditor* mOrigin;
  96. LLMenuItemCallGL* mMenuItem;
  97. std::string mWord;
  98. S32 mWordPositionStart;
  99. S32 mWordPositionEnd;
  100. };
  101. std::vector<S32> getMisspelledWordsPositions();
  102. virtual void spellReplace(SpellMenuBind* data);
  103. virtual void insert(std::string what, S32 where);
  104. // LLEditMenuHandler overrides
  105. void cut() override;
  106. bool canCut() const override;
  107. void copy() override;
  108. bool canCopy() const override;
  109. void paste() override;
  110. bool canPaste() const override;
  111. void doDelete() override;
  112. bool canDoDelete() const override;
  113. void selectAll() override;
  114. LL_INLINE bool canSelectAll() const override { return true; }
  115. void deselect() override;
  116. LL_INLINE bool canDeselect() const override { return hasSelection(); }
  117. // New methods
  118. virtual void updatePrimary();
  119. virtual void copyPrimary();
  120. virtual void pastePrimary();
  121. virtual bool canPastePrimary() const;
  122. // LLView overrides
  123. void draw() override;
  124. void reshape(S32 width, S32 height, bool call_from_parent = true) override;
  125. void onFocusReceived() override;
  126. void onFocusLost() override;
  127. void setEnabled(bool enabled) override;
  128. LL_INLINE bool setTextArg(const std::string& key,
  129. const std::string& text) override
  130. {
  131. mText.setArg(key, text);
  132. return true;
  133. }
  134. LL_INLINE bool setLabelArg(const std::string& key,
  135. const std::string& text) override
  136. {
  137. mLabel.setArg(key, text);
  138. return true;
  139. }
  140. // LLUICtrl overrides
  141. void clear() override;
  142. void onTabInto() override;
  143. void setFocus(bool b) override;
  144. void setRect(const LLRect& rect) override;
  145. LL_INLINE bool acceptsTextInput() const override { return true; }
  146. void onCommit() override;
  147. // Returns true if user changed value at all
  148. LL_INLINE bool isDirty() const override { return mText.getString() != mPrevText; }
  149. // Clear dirty state
  150. LL_INLINE void resetDirty() override { mPrevText = mText.getString(); }
  151. // Assumes UTF8 text
  152. LL_INLINE void setValue(const LLSD& value) override { setText(value.asString()); }
  153. LL_INLINE LLSD getValue() const override { return LLSD(getText()); }
  154. // New methods
  155. LL_INLINE void setLabel(const std::string& label) { mLabel = label; }
  156. void setText(const std::string& new_text);
  157. LL_INLINE const std::string& getText() const { return mText.getString(); }
  158. LL_INLINE const LLWString& getWText() const override { return mText.getWString(); }
  159. // trimmed text with paragraphs converted to newlines
  160. LLWString getConvertedText() const;
  161. LL_INLINE S32 getLength() const { return mText.length(); }
  162. LL_INLINE S32 getCursor() const { return mCursorPos; }
  163. void setCursor(S32 pos);
  164. void setCursorToEnd();
  165. void resetScrollPosition();
  166. // Selects characters 'start' to 'end'.
  167. void setSelection(S32 start, S32 end);
  168. LL_INLINE void setCommitOnFocusLost(bool b) { mCommitOnFocusLost = b; }
  169. LL_INLINE void setRevertOnEsc(bool b) { mRevertOnEsc = b; }
  170. LL_INLINE void setCursorColor(const LLColor4& c) { mCursorColor = c; }
  171. LL_INLINE const LLColor4& getCursorColor() const { return mCursorColor; }
  172. LL_INLINE void setFgColor(const LLColor4& c) { mFgColor = c; }
  173. LL_INLINE void setReadOnlyFgColor(const LLColor4& c) { mReadOnlyFgColor = c; }
  174. LL_INLINE void setTentativeFgColor(const LLColor4& c) { mTentativeFgColor = c; }
  175. LL_INLINE void setWriteableBgColor(const LLColor4& c) { mWriteableBgColor = c; }
  176. LL_INLINE void setReadOnlyBgColor(const LLColor4& c) { mReadOnlyBgColor = c; }
  177. LL_INLINE void setFocusBgColor(const LLColor4& c) { mFocusBgColor = c; }
  178. LL_INLINE void setSpellCheck(bool b) { mSpellCheck = b; }
  179. LL_INLINE const LLColor4& getFgColor() const { return mFgColor; }
  180. LL_INLINE const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor; }
  181. LL_INLINE const LLColor4& getTentativeFgColor() const { return mTentativeFgColor; }
  182. LL_INLINE const LLColor4& getWriteableBgColor() const { return mWriteableBgColor; }
  183. LL_INLINE const LLColor4& getReadOnlyBgColor() const { return mReadOnlyBgColor; }
  184. LL_INLINE const LLColor4& getFocusBgColor() const { return mFocusBgColor; }
  185. LL_INLINE bool getSpellCheck() { return mSpellCheck; }
  186. LL_INLINE void setIgnoreArrowKeys(bool b) { mIgnoreArrowKeys = b; }
  187. LL_INLINE void setIgnoreTab(bool b) { mIgnoreTab = b; }
  188. LL_INLINE void setPassDelete(bool b) { mPassDelete = b; }
  189. void setDrawAsterixes(bool b);
  190. LL_INLINE bool getDrawAsterixes() { return mDrawAsterixes; }
  191. // Get the cursor position of the beginning/end of the prev/next word in
  192. // the text
  193. S32 prevWordPos(S32 cursor_pos) const;
  194. S32 nextWordPos(S32 cursor_pos) const;
  195. bool getWordBoundriesAt(S32 at, S32* word_begin, S32* word_length) const;
  196. LL_INLINE bool hasSelection() const { return mSelectionStart != mSelectionEnd; }
  197. void startSelection();
  198. void endSelection();
  199. void extendSelection(S32 new_cursor_pos);
  200. void deleteSelection();
  201. LL_INLINE void setHandleEditKeysDirectly(bool b) { mHandleEditKeysDirectly = b; }
  202. void setSelectAllonFocusReceived(bool b);
  203. void setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor*,
  204. void*));
  205. void setScrolledCallback(void (*scrolled_callback)(LLLineEditor*, void*),
  206. void* userdata);
  207. void setOnHandleKeyCallback(bool (*callback)(KEY, MASK, LLLineEditor*,
  208. void*),
  209. void* userdata);
  210. void setMaxTextLength(S32 max_text_length);
  211. // Used to specify room for children before or after text.
  212. void setTextPadding(S32 left, S32 right);
  213. // Prevalidation controls which keystrokes can affect the editor
  214. void setPrevalidate(bool (*func)(const LLWString&));
  215. static bool prevalidateFloat(const LLWString& str);
  216. static bool prevalidateInt(const LLWString& str);
  217. static bool prevalidatePositiveS32(const LLWString& str);
  218. static bool prevalidateNonNegativeS32(const LLWString& str);
  219. static bool prevalidateAlphaNum(const LLWString& str);
  220. static bool prevalidateAlphaNumSpace(const LLWString& str);
  221. static bool prevalidatePrintableNotPipe(const LLWString& str);
  222. static bool prevalidatePrintableNoSpace(const LLWString& str);
  223. static bool prevalidateASCII(const LLWString& str);
  224. static bool postvalidateFloat(const std::string& str);
  225. // Line history support:
  226. // Switches line history on or off
  227. LL_INLINE void setEnableLineHistory(bool enabled) { mHaveHistory = enabled; }
  228. // Stores current line in history
  229. void updateHistory();
  230. LL_INLINE void setReplaceNewlinesWithSpaces(bool b) { mReplaceNewlinesWithSpaces = b; }
  231. private:
  232. void pasteHelper(bool is_primary);
  233. void removeChar();
  234. void addChar(llwchar c);
  235. S32 calculateCursorFromMouse(S32 local_mouse_x);
  236. void setCursorAtLocalPos(S32 local_mouse_x);
  237. S32 findPixelNearestPos(S32 cursor_offset = 0) const;
  238. void reportBadKeystroke();
  239. bool handleSpecialKey(KEY key, MASK mask);
  240. bool handleSelectionKey(KEY key, MASK mask);
  241. bool handleControlKey(KEY key, MASK mask);
  242. S32 handleCommitKey(KEY key, MASK mask);
  243. void updateAllowingLanguageInput();
  244. bool hasPreeditString() const;
  245. // Implementation (overrides) of LLPreeditor
  246. void resetPreedit() override;
  247. void updatePreedit(const LLWString& preedit_string,
  248. const segment_lengths_t& preedit_segment_lengths,
  249. const standouts_t& preedit_standouts,
  250. S32 caret_position) override;
  251. void markAsPreedit(S32 position, S32 length) override;
  252. void getPreeditRange(S32* position, S32* length) const override;
  253. void getSelectionRange(S32* position, S32* length) const override;
  254. bool getPreeditLocation(S32 query_position, LLCoordGL* coord,
  255. LLRect* bounds, LLRect* control) const override;
  256. S32 getPreeditFontSize() const override;
  257. // Private helper class
  258. class LLLineEditorRollback
  259. {
  260. public:
  261. LLLineEditorRollback(LLLineEditor* ed)
  262. : mCursorPos(ed->mCursorPos),
  263. mScrollHPos(ed->mScrollHPos),
  264. mIsSelecting(ed->mIsSelecting),
  265. mSelectionStart(ed->mSelectionStart),
  266. mSelectionEnd(ed->mSelectionEnd)
  267. {
  268. mText = ed->getText();
  269. }
  270. void doRollback(LLLineEditor* ed)
  271. {
  272. ed->mCursorPos = mCursorPos;
  273. ed->mScrollHPos = mScrollHPos;
  274. ed->mIsSelecting = mIsSelecting;
  275. ed->mSelectionStart = mSelectionStart;
  276. ed->mSelectionEnd = mSelectionEnd;
  277. ed->mText = mText;
  278. ed->mPrevText = mText;
  279. }
  280. LL_INLINE std::string getText() { return mText; }
  281. private:
  282. std::string mText;
  283. S32 mCursorPos;
  284. S32 mScrollHPos;
  285. bool mIsSelecting;
  286. S32 mSelectionStart;
  287. S32 mSelectionEnd;
  288. };
  289. // Utility on top of LLUI::getUIImage, looks up a named image in a given
  290. // XML node and returns it if possible or returns a given default image if
  291. // anything in the process fails.
  292. static LLUIImagePtr parseImage(std::string name, LLXMLNodePtr from,
  293. LLUIImagePtr def);
  294. // Context menu actions
  295. static void spellCorrect(void* data);
  296. static void spellShow(void* data);
  297. static void spellAdd(void* data);
  298. static void spellIgnore(void* data);
  299. void drawMisspelled(LLRect background);
  300. protected:
  301. LLUIString mText; // The string being edited.
  302. std::string mPrevText; // Saved string for 'ESC' revert
  303. // Text label that is visible when no user text provided
  304. LLUIString mLabel;
  305. // Spell checking
  306. // Saved string so we know whether to respell or not
  307. std::string mPrevSpelledText;
  308. // Where all the misspelled words are
  309. std::vector<S32> mMisspellLocations;
  310. // The position of the first character, stored so we know when to update
  311. S32 mSpellCheckStart;
  312. // The location of the last character
  313. S32 mSpellCheckEnd;
  314. // Set in xui as "spell_check". Default value for a field
  315. bool mSpellCheck;
  316. // Whether to highlight misspelled words or not
  317. bool mShowMisspelled;
  318. LLFrameTimer mSpellTimer;
  319. // To keep track of what we have to remove before rebuilding the context
  320. // menu
  321. std::vector<SpellMenuBind*> mSuggestionMenuItems;
  322. // Line history support:
  323. typedef std::vector<std::string> line_history_t;
  324. line_history_t mLineHistory; // Line history storage
  325. // Currently browsed history line
  326. line_history_t::iterator mCurrentHistoryLine;
  327. // Flag for enabled line history
  328. bool mHaveHistory;
  329. // Selection for clipboard operations
  330. bool mIsSelecting;
  331. S32 mSelectionStart;
  332. S32 mSelectionEnd;
  333. S32 mLastSelectionX;
  334. S32 mLastSelectionY;
  335. S32 mLastSelectionStart;
  336. S32 mLastSelectionEnd;
  337. LLViewBorder* mBorder;
  338. const LLFontGL* mGLFont;
  339. // Max length of the UTF8 string in bytes
  340. S32 mMaxLengthBytes;
  341. // I-beam is just after the mCursorPos-th character.
  342. S32 mCursorPos;
  343. // Horizontal offset from the start of mText. Used for scrolling.
  344. S32 mScrollHPos;
  345. LLFrameTimer mScrollTimer;
  346. // Used to reserve space before the beginning of the text for children
  347. S32 mTextPadLeft;
  348. // Used to reserve space after the end of the text for children
  349. S32 mTextPadRight;
  350. S32 mMinHPixels;
  351. S32 mMaxHPixels;
  352. bool mCommitOnFocusLost;
  353. bool mRevertOnEsc;
  354. void (*mKeystrokeCallback)(LLLineEditor* caller,
  355. void* userdata);
  356. void (*mScrolledCallback)(LLLineEditor* caller,
  357. void* userdata);
  358. void* mScrolledCallbackData;
  359. bool (*mOnHandleKeyCallback)(KEY, MASK,
  360. LLLineEditor*, void*);
  361. void* mOnHandleKeyData;
  362. bool (*mPrevalidateFunc)(const LLWString& str);
  363. LLFrameTimer mKeystrokeTimer;
  364. LLColor4 mCursorColor;
  365. LLColor4 mFgColor;
  366. LLColor4 mReadOnlyFgColor;
  367. LLColor4 mTentativeFgColor;
  368. LLColor4 mWriteableBgColor;
  369. LLColor4 mReadOnlyBgColor;
  370. LLColor4 mFocusBgColor;
  371. S32 mBorderThickness;
  372. LLWString mPreeditWString;
  373. LLWString mPreeditOverwrittenWString;
  374. std::vector<S32> mPreeditPositions;
  375. LLPreeditor::standouts_t mPreeditStandouts;
  376. bool mIgnoreArrowKeys;
  377. bool mIgnoreTab;
  378. bool mDrawAsterixes;
  379. // If true, the standard edit keys (Ctrl-X, Delete, etc) are handled here
  380. // instead of routed by the menu system:
  381. bool mHandleEditKeysDirectly;
  382. bool mSelectAllonFocusReceived;
  383. bool mPassDelete;
  384. bool mReadOnly;
  385. private:
  386. // If false, will replace pasted newlines with paragraph symbol.
  387. bool mReplaceNewlinesWithSpaces;
  388. // Instances that by default point to the statics but can be overidden in
  389. // XML.
  390. LLUIImagePtr mImage;
  391. // Global instance used as default for member instance above.
  392. static LLUIImagePtr sImage;
  393. };
  394. // A line editor with a button to clear it and a callback to call on every edit
  395. // event.
  396. class LLSearchEditor final : public LLUICtrl, public LLEditMenuHandler
  397. {
  398. public:
  399. LLSearchEditor(const std::string& name, const LLRect& rect,
  400. S32 max_length);
  401. void draw() override;
  402. const std::string& getTag() const override;
  403. LLXMLNodePtr getXML(bool save_children = true) const override;
  404. static LLView* fromXML(LLXMLNodePtr nodep, LLView* parentp,
  405. LLUICtrlFactory*);
  406. LL_INLINE void setText(const std::string& new_text) { mSearchLineEditor->setText(new_text); }
  407. LL_INLINE const std::string& getText() const { return mSearchLineEditor->getText(); }
  408. void setSearchCallback(void (*cb)(const std::string&, void*),
  409. void* userdata);
  410. // LLUICtrl overrides since we want the callback to apply to the input line
  411. void setCommitCallback(void (*cb)(LLUICtrl*, void*));
  412. void setCallbackUserData(void* data)
  413. {
  414. mCommitCallbackUserData = data;
  415. }
  416. LL_INLINE void setValue(const LLSD& value) override { mSearchLineEditor->setValue(value); }
  417. LL_INLINE LLSD getValue() const override { return mSearchLineEditor->getValue(); }
  418. LL_INLINE bool setTextArg(const std::string& key,
  419. const std::string& text) override
  420. {
  421. return mSearchLineEditor->setTextArg(key, text);
  422. }
  423. LL_INLINE bool setLabelArg(const std::string& key,
  424. const std::string& text) override
  425. {
  426. return mSearchLineEditor->setLabelArg(key, text);
  427. }
  428. void clear() override;
  429. private:
  430. // These are wrappers around the LLSearchEditor commits
  431. static void onSearchEditCommit(LLUICtrl* ctrl, void* data);
  432. static void onSearchEditKeystroke(LLLineEditor* caller, void* data);
  433. static void onClearSearch(void* user_data);
  434. private:
  435. LLLineEditor* mSearchLineEditor;
  436. LLButton* mClearSearchButton;
  437. void (*mLineCommitCallback)(LLUICtrl* ctrl, void* user_data);
  438. void (*mSearchCallback)(const std::string& search_string,
  439. void* user_data);
  440. void* mCommitCallbackUserData;
  441. };
  442. #endif // LL_LINEEDITOR_