Torque3D Documentation / _generateds / guiTextEditCtrl.cpp

guiTextEditCtrl.cpp

Engine/source/gui/controls/guiTextEditCtrl.cpp

More...

Public Functions

ConsoleDocClass(GuiTextEditCtrl , "@brief A component that places <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> text entry box on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">screen.\n\n</a>" "Fonts and sizes are changed using profiles. The text <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> can be set or entered by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">user.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguitexteditctrl/">GuiTextEditCtrl</a>(MessageHud_Edit)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      text = \"Hello World\";\n" "      validate = \"validateCommand();\"\n" "      escapeCommand = \"escapeCommand();\";\n" "      historySize = \"5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      tabComplete = \"true\";\n" "      deniedSound = \"DeniedSoundProfile\";\n" "      sinkAllKeyEvents = \"true\";\n" "      password = \"true\";\n" "      passwordMask = \"*\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "       //Properties not specific <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> have been omitted from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example.\n</a>" "   };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControls\n</a>" )
DefineEngineMethod(GuiTextEditCtrl , clearSelectedText , void , () , "@brief Unselects all selected text in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> unselect all of its selected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text\n</a>" "%thisGuiTextEditCtrl.clearSelectedText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )
DefineEngineMethod(GuiTextEditCtrl , forceValidateText , void , () , "@brief Force <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> validation <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> force <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> validation of its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text.\n</a>" "%thisGuiTextEditCtrl.forceValidateText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )
DefineEngineMethod(GuiTextEditCtrl , getCursorPos , S32 , () )
DefineEngineMethod(GuiTextEditCtrl , getText , const char * , () )
DefineEngineMethod(GuiTextEditCtrl , invalidText , void , (bool playSound) , (true) , "@brief <a href="/coding/class/classtrigger/">Trigger</a> the invalid sound and make the box red.nn" "@param playSound Play the invalid text sound or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.n</a>" )
DefineEngineMethod(GuiTextEditCtrl , isAllTextSelected , bool , () , "@brief Checks <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> all text in the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Check <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> all text has been selected or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.\n</a>" "% allSelected, otherwise <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">false.\n\n</a>" " @see <a href="/coding/class/classguicontrol/">GuiControl</a>" )
DefineEngineMethod(GuiTextEditCtrl , isValidText , bool , () , "@brief Returns <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the text is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> valid or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.n</a>" "@Return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> text is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> valid, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not.nn" )
DefineEngineMethod(GuiTextEditCtrl , selectAllText , void , () , "@brief Selects all text within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> select all of its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text.\n</a>" "%thisGuiTextEditCtrl.selectAllText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )
DefineEngineMethod(GuiTextEditCtrl , setCursorPos , void , (S32 position) , "@brief Sets the text <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> at the defined position within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@param position Text position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the text <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cursor.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n</a>" "% position)
DefineEngineMethod(GuiTextEditCtrl , setText , void , (const char *text) , "@brief Sets the text in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@param text Text <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> place in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the text <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">display\n</a>" "% text)
DefineEngineMethod(GuiTextEditCtrl , validText , void , () , "@brief Restores the box <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> normal color.nn" )
IMPLEMENT_CALLBACK(GuiTextEditCtrl , onReturn , void , () , () , "@brief Called when the 'Return' or 'Enter' key is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pressed.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Return or Enter key was pressed, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiTextEditCtrl::onReturn(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the onReturn callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )
IMPLEMENT_CALLBACK(GuiTextEditCtrl , onTabComplete , void , (const char *val) , (val) , "@brief Called <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> tabComplete is true, and the 'tab' key is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pressed.\n\n</a>" " @param val <a href="/coding/class/classinput/">Input</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mimick the '1' sent by the actual tab key button <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">press.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Tab key has been pressed, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiTextEditCtrl::onTabComplete(%this,%val)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the onTabComplete callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )
IMPLEMENT_CALLBACK(GuiTextEditCtrl , onValidate , void , () , () , "@brief Called whenever the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">validated.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> gets validated, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur\n</a>" "GuiTextEditCtrl::onValidated(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">validated\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )

Detailed Description

Public Functions

ConsoleDocClass(GuiTextEditCtrl , "@brief A component that places <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> text entry box on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">screen.\n\n</a>" "Fonts and sizes are changed using profiles. The text <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> can be set or entered by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">user.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classguitexteditctrl/">GuiTextEditCtrl</a>(MessageHud_Edit)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      text = \"Hello World\";\n" "      validate = \"validateCommand();\"\n" "      escapeCommand = \"escapeCommand();\";\n" "      historySize = \"5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "      tabComplete = \"true\";\n" "      deniedSound = \"DeniedSoundProfile\";\n" "      sinkAllKeyEvents = \"true\";\n" "      password = \"true\";\n" "      passwordMask = \"*\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "       //Properties not specific <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> have been omitted from this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example.\n</a>" "   };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControls\n</a>" )

DefineEngineMethod(GuiTextEditCtrl , clearSelectedText , void , () , "@brief Unselects all selected text in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> unselect all of its selected <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text\n</a>" "%thisGuiTextEditCtrl.clearSelectedText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )

DefineEngineMethod(GuiTextEditCtrl , forceValidateText , void , () , "@brief Force <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> validation <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> force <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> validation of its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text.\n</a>" "%thisGuiTextEditCtrl.forceValidateText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )

DefineEngineMethod(GuiTextEditCtrl , getCursorPos , S32 , () )

DefineEngineMethod(GuiTextEditCtrl , getText , const char * , () )

DefineEngineMethod(GuiTextEditCtrl , invalidText , void , (bool playSound) , (true) , "@brief <a href="/coding/class/classtrigger/">Trigger</a> the invalid sound and make the box red.nn" "@param playSound Play the invalid text sound or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.n</a>" )

DefineEngineMethod(GuiTextEditCtrl , isAllTextSelected , bool , () , "@brief Checks <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> all text in the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">selected.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Check <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> all text has been selected or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.\n</a>" "% allSelected, otherwise <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">false.\n\n</a>" " @see <a href="/coding/class/classguicontrol/">GuiControl</a>" )

DefineEngineMethod(GuiTextEditCtrl , isValidText , bool , () , "@brief Returns <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the text is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> valid or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.n</a>" "@Return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> text is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> valid, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not.nn" )

DefineEngineMethod(GuiTextEditCtrl , selectAllText , void , () , "@brief Selects all text within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Inform the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> select all of its <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">text.\n</a>" "%thisGuiTextEditCtrl.selectAllText();\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/class/classguicontrol/">GuiControl</a>" )

DefineEngineMethod(GuiTextEditCtrl , setCursorPos , void , (S32 position) , "@brief Sets the text <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> at the defined position within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@param position Text position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set the text <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cursor.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n</a>" "% position)

DefineEngineMethod(GuiTextEditCtrl , setText , void , (const char *text) , "@brief Sets the text in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n\n</a>" "@param text Text <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> place in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Define the text <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">display\n</a>" "% text)

DefineEngineMethod(GuiTextEditCtrl , validText , void , () , "@brief Restores the box <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> normal color.nn" )

IMPLEMENT_CALLBACK(GuiTextEditCtrl , onReturn , void , () , () , "@brief Called when the 'Return' or 'Enter' key is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pressed.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Return or Enter key was pressed, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiTextEditCtrl::onReturn(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the onReturn callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )

IMPLEMENT_CALLBACK(GuiTextEditCtrl , onTabComplete , void , (const char *val) , (val) , "@brief Called <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> tabComplete is true, and the 'tab' key is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pressed.\n\n</a>" " @param val <a href="/coding/class/classinput/">Input</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mimick the '1' sent by the actual tab key button <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">press.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Tab key has been pressed, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur.\n</a>" "GuiTextEditCtrl::onTabComplete(%this,%val)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the onTabComplete callback <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occurs\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )

IMPLEMENT_CALLBACK(GuiTextEditCtrl , onValidate , void , () , () , "@brief Called whenever the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">validated.\n\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// The <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> gets validated, causing the callback <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">occur\n</a>" "GuiTextEditCtrl::onValidated(%this)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Code <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> run when the <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">validated\n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTextCtrl\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControl\n\n</a>" )

IMPLEMENT_CONOBJECT(GuiTextEditCtrl )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25#include "gui/controls/guiTextEditCtrl.h"
  26
  27#include "console/consoleTypes.h"
  28#include "console/console.h"
  29#include "gui/core/guiCanvas.h"
  30#include "gui/controls/guiMLTextCtrl.h"
  31#include "gui/core/guiDefaultControlRender.h"
  32#include "gfx/gfxDevice.h"
  33#include "gfx/gfxDrawUtil.h"
  34#include "core/frameAllocator.h"
  35#include "sfx/sfxTrack.h"
  36#include "sfx/sfxTypes.h"
  37#include "sfx/sfxSystem.h"
  38#include "core/strings/unicode.h"
  39#include "console/engineAPI.h"
  40
  41IMPLEMENT_CONOBJECT(GuiTextEditCtrl);
  42
  43ConsoleDocClass( GuiTextEditCtrl,
  44   "@brief A component that places a text entry box on the screen.\n\n"
  45
  46   "Fonts and sizes are changed using profiles. The text value can be set or entered by a user.\n\n"
  47
  48   "@tsexample\n"
  49   "   new GuiTextEditCtrl(MessageHud_Edit)\n"
  50   "  {\n"
  51   "      text = \"Hello World\";\n"
  52   "      validate = \"validateCommand();\"\n"
  53   "      escapeCommand = \"escapeCommand();\";\n"
  54   "      historySize = \"5\";\n"
  55   "      tabComplete = \"true\";\n"
  56   "      deniedSound = \"DeniedSoundProfile\";\n"
  57   "      sinkAllKeyEvents = \"true\";\n"
  58   "      password = \"true\";\n"
  59   "      passwordMask = \"*\";\n"
  60   "       //Properties not specific to this control have been omitted from this example.\n"
  61   "   };\n"
  62   "@endtsexample\n\n"
  63
  64   "@see GuiTextCtrl\n"
  65   "@see GuiControl\n\n"
  66
  67   "@ingroup GuiControls\n"
  68);
  69
  70IMPLEMENT_CALLBACK( GuiTextEditCtrl, onTabComplete, void, (const char* val),( val ),
  71   "@brief Called if tabComplete is true, and the 'tab' key is pressed.\n\n"
  72   "@param val Input to mimick the '1' sent by the actual tab key button press.\n"
  73   "@tsexample\n"
  74   "// Tab key has been pressed, causing the callback to occur.\n"
  75   "GuiTextEditCtrl::onTabComplete(%this,%val)\n"
  76   "  {\n"
  77   "     //Code to run when the onTabComplete callback occurs\n"
  78   "  }\n"
  79   "@endtsexample\n\n"
  80   "@see GuiTextCtrl\n"
  81   "@see GuiControl\n\n"
  82);
  83
  84IMPLEMENT_CALLBACK( GuiTextEditCtrl, onReturn, void, (),(),
  85   "@brief Called when the 'Return' or 'Enter' key is pressed.\n\n"
  86   "@tsexample\n"
  87   "// Return or Enter key was pressed, causing the callback to occur.\n"
  88   "GuiTextEditCtrl::onReturn(%this)\n"
  89   "  {\n"
  90   "     // Code to run when the onReturn callback occurs\n"
  91   "  }\n"
  92   "@endtsexample\n\n"
  93   "@see GuiTextCtrl\n"
  94   "@see GuiControl\n\n"
  95);
  96
  97IMPLEMENT_CALLBACK( GuiTextEditCtrl, onValidate, void, (),(),
  98   "@brief Called whenever the control is validated.\n\n"
  99   "@tsexample\n"
 100   "// The control gets validated, causing the callback to occur\n"
 101   "GuiTextEditCtrl::onValidated(%this)\n"
 102   "  {\n"
 103   "     // Code to run when the control is validated\n"
 104   "  }\n"
 105   "@endtsexample\n\n"
 106   "@see GuiTextCtrl\n"
 107   "@see GuiControl\n\n"
 108);
 109
 110GuiTextEditCtrl::GuiTextEditCtrl()
 111{
 112   mInsertOn = true;
 113   mBlockStart = 0;
 114   mBlockEnd = 0;
 115   mCursorPos = 0;
 116   mCursorOn = false;
 117   mNumFramesElapsed = 0;
 118
 119   mDragHit = false;
 120   mTabComplete = false;
 121   mScrollDir = 0;
 122
 123   mUndoBlockStart = 0;
 124   mUndoBlockEnd = 0;
 125   mUndoCursorPos = 0;
 126   mPasswordText = false;
 127
 128   mSinkAllKeyEvents = false;
 129
 130   mActive = true;
 131
 132   mTextValid = true;
 133
 134   mTextOffsetReset = true;
 135
 136   mHistoryDirty = false;
 137   mHistorySize = 0;
 138   mHistoryLast = -1;
 139   mHistoryIndex = 0;
 140   mHistoryBuf = NULL;
 141
 142   mDoubleClickTimeMS = 50;
 143   mMouseUpTime = 0;
 144
 145   mPlaceholderText = StringTable->EmptyString();
 146
 147#if defined(__MACOSX__)
 148   UTF8  bullet[4] = { UTF8(0xE2), UTF8(0x80), UTF8(0xA2), 0 };
 149   
 150   mPasswordMask = StringTable->insert( bullet );
 151#else
 152   mPasswordMask = StringTable->insert( "*" );
 153#endif
 154   Sim::findObject( "InputDeniedSound", mDeniedSound );
 155}
 156
 157GuiTextEditCtrl::~GuiTextEditCtrl()
 158{
 159   //delete the history buffer if it exists
 160   if (mHistoryBuf)
 161   {
 162      for (S32 i = 0; i < mHistorySize; i++)
 163         delete [] mHistoryBuf[i];
 164
 165      delete [] mHistoryBuf;
 166   }
 167}
 168
 169void GuiTextEditCtrl::initPersistFields()
 170{
 171   addProtectedField("placeholderText", TypeCaseString, Offset(mPlaceholderText, GuiTextEditCtrl), setPlaceholderText, getPlaceholderText,
 172      "The text to show on the control.");
 173
 174   addGroup( "Text Input" );
 175   
 176      addField("validate",          TypeRealString,Offset(mValidateCommand,   GuiTextEditCtrl), "Script command to be called when the first validater is lost.\n");
 177      addField("escapeCommand",     TypeRealString,Offset(mEscapeCommand,     GuiTextEditCtrl), "Script command to be called when the Escape key is pressed.\n");
 178      addField("historySize",       TypeS32,       Offset(mHistorySize,       GuiTextEditCtrl), "How large of a history buffer to maintain.\n");
 179      addField("tabComplete",       TypeBool,      Offset(mTabComplete,       GuiTextEditCtrl), "If true, when the 'tab' key is pressed, it will act as if the Enter key was pressed on the control.\n");
 180      addField("deniedSound",       TypeSFXTrackName, Offset(mDeniedSound, GuiTextEditCtrl), "If the attempted text cannot be entered, this sound effect will be played.\n");
 181      addField("sinkAllKeyEvents",  TypeBool,      Offset(mSinkAllKeyEvents,  GuiTextEditCtrl), "If true, every key event will act as if the Enter key was pressed.\n");
 182      addField("password",          TypeBool,      Offset(mPasswordText,      GuiTextEditCtrl), "If true, all characters entered will be stored in the control, however will display as the character stored in passwordMask.\n");
 183      addField("passwordMask",      TypeString,    Offset(mPasswordMask,      GuiTextEditCtrl), "If 'password' is true, this is the character that will be used to mask the characters in the control.\n");
 184      
 185   endGroup( "Text Input" );
 186
 187   Parent::initPersistFields();
 188}
 189
 190bool GuiTextEditCtrl::onAdd()
 191{
 192   if ( ! Parent::onAdd() )
 193      return false;
 194
 195   //create the history buffer
 196   if ( mHistorySize > 0 )
 197   {
 198      mHistoryBuf = new UTF16*[mHistorySize];
 199      for ( S32 i = 0; i < mHistorySize; i++ )
 200      {
 201         mHistoryBuf[i] = new UTF16[GuiTextCtrl::MAX_STRING_LENGTH + 1];
 202         mHistoryBuf[i][0] = '\0';
 203      }
 204   }
 205
 206   if( mText && mText[0] )
 207   {
 208      setText(mText);
 209   }
 210
 211   return true;
 212}
 213
 214void GuiTextEditCtrl::onStaticModified(const char* slotName, const char* newValue)
 215{
 216   if(!dStricmp(slotName, "text"))
 217      setText(mText);
 218}
 219
 220void GuiTextEditCtrl::execConsoleCallback()
 221{
 222   // Execute the console command!
 223   Parent::execConsoleCallback();
 224
 225   // Update the console variable:
 226   if ( mConsoleVariable[0] )
 227      Con::setVariable(mConsoleVariable, mTextBuffer.getPtr8());
 228}
 229
 230void GuiTextEditCtrl::updateHistory( StringBuffer *inTxt, bool moveIndex )
 231{
 232   if(!mHistorySize)
 233      return;
 234
 235   const UTF16* txt = inTxt->getPtr();
 236   
 237   // Reject empty strings.
 238
 239   if( !txt || !txt[ 0 ] )
 240      return;
 241
 242   // see if it's already in
 243   if(mHistoryLast == -1 || String::compare(txt, mHistoryBuf[mHistoryLast]))
 244   {
 245      if(mHistoryLast == mHistorySize-1) // we're at the history limit... shuffle the pointers around:
 246      {
 247         UTF16 *first = mHistoryBuf[0];
 248         for(U32 i = 0; i < mHistorySize - 1; i++)
 249            mHistoryBuf[i] = mHistoryBuf[i+1];
 250         mHistoryBuf[mHistorySize-1] = first;
 251         if(mHistoryIndex > 0)
 252            mHistoryIndex--;
 253      }
 254      else
 255         mHistoryLast++;
 256
 257      inTxt->getCopy(mHistoryBuf[mHistoryLast], GuiTextCtrl::MAX_STRING_LENGTH);
 258      mHistoryBuf[mHistoryLast][GuiTextCtrl::MAX_STRING_LENGTH] = '\0';
 259   }
 260
 261   if(moveIndex)
 262      mHistoryIndex = mHistoryLast + 1;
 263}
 264
 265void GuiTextEditCtrl::getText( char *dest )
 266{
 267   if ( dest )
 268      mTextBuffer.getCopy8((UTF8*)dest, GuiTextCtrl::MAX_STRING_LENGTH+1);
 269}
 270
 271void GuiTextEditCtrl::getRenderText(char *dest)
 272{
 273    getText( dest );
 274}
 275 
 276void GuiTextEditCtrl::setText( const UTF8 *txt )
 277{
 278   if(txt && txt[0] != 0)
 279   {
 280      Parent::setText(txt);
 281      mTextBuffer.set( txt );
 282   }
 283   else
 284      mTextBuffer.set( "" );
 285
 286   mCursorPos = mTextBuffer.length();
 287}
 288
 289void GuiTextEditCtrl::setText( const UTF16* txt)
 290{
 291   if(txt && txt[0] != 0)
 292   {
 293      UTF8* txt8 = createUTF8string( txt );
 294      Parent::setText( txt8 );
 295      delete[] txt8;
 296      mTextBuffer.set( txt );
 297   }
 298   else
 299   {
 300      Parent::setText("");
 301      mTextBuffer.set("");
 302   }
 303   
 304   mCursorPos = mTextBuffer.length();   
 305}
 306
 307bool GuiTextEditCtrl::isAllTextSelected()
 308{
 309   if( mBlockStart == 0 && mBlockEnd == mTextBuffer.length() )
 310      return true;
 311   else
 312      return false;
 313}
 314
 315void GuiTextEditCtrl::selectAllText()
 316{
 317   mBlockStart = 0;
 318   mBlockEnd = mTextBuffer.length();
 319   setUpdate();
 320}
 321
 322void GuiTextEditCtrl::clearSelectedText()
 323{
 324   mBlockStart = 0;
 325   mBlockEnd = 0;
 326   setUpdate();
 327}
 328
 329void GuiTextEditCtrl::forceValidateText()
 330{
 331   if( mValidateCommand.isNotEmpty() )
 332      evaluate( mValidateCommand );
 333}
 334
 335void GuiTextEditCtrl::setCursorPos( const S32 newPos )
 336{
 337   S32 charCount = mTextBuffer.length();
 338   S32 realPos = newPos > charCount ? charCount : newPos < 0 ? 0 : newPos;
 339   if ( realPos != mCursorPos )
 340   {
 341      mCursorPos = realPos;
 342      setUpdate();
 343   }
 344}
 345
 346S32 GuiTextEditCtrl::calculateCursorPos( const Point2I &globalPos )
 347{
 348   Point2I ctrlOffset = localToGlobalCoord( Point2I( 0, 0 ) );
 349   S32 charLength = 0;
 350   S32 curX;
 351
 352   curX = globalPos.x - ctrlOffset.x;
 353   setUpdate();
 354
 355   //if the cursor is too far to the left
 356   if ( curX < 0 )
 357      return -1;
 358
 359   //if the cursor is too far to the right
 360   if ( curX >= ctrlOffset.x + getExtent().x )
 361      return -2;
 362
 363   curX = globalPos.x - mTextOffset.x;
 364   S32 count=0;
 365   if(mTextBuffer.length() == 0)
 366      return 0;
 367
 368   for(count=0; count<mTextBuffer.length(); count++)
 369   {
 370      UTF16 c = mTextBuffer.getChar(count);
 371      if(!mPasswordText && !mProfile->mFont->isValidChar(c))
 372         continue;
 373         
 374      if(mPasswordText)
 375         charLength += mProfile->mFont->getCharXIncrement( mPasswordMask[0] );
 376      else
 377         charLength += mProfile->mFont->getCharXIncrement( c );
 378
 379      if ( charLength > curX )
 380         break;      
 381   }
 382
 383   return count;
 384}
 385
 386void GuiTextEditCtrl::onMouseDown( const GuiEvent &event )
 387{
 388   if(!isActive())
 389      return;
 390   mDragHit = false;
 391
 392   // If we have a double click, select all text.  Otherwise
 393   // act as before by clearing any selection.
 394   bool doubleClick = (event.mouseClickCount > 1 && Platform::getRealMilliseconds() - mMouseUpTime > mDoubleClickTimeMS);
 395   if(doubleClick)
 396   {
 397      selectAllText();
 398
 399   } else
 400   {
 401      //undo any block function
 402      mBlockStart = 0;
 403      mBlockEnd = 0;
 404   }
 405
 406   //find out where the cursor should be
 407   S32 pos = calculateCursorPos( event.mousePoint );
 408
 409   // if the position is to the left
 410   if ( pos == -1 )
 411      mCursorPos = 0;
 412   else if ( pos == -2 ) //else if the position is to the right
 413      mCursorPos = mTextBuffer.length();
 414   else //else set the mCursorPos
 415      mCursorPos = pos;
 416
 417   //save the mouseDragPos
 418   mMouseDragStart = mCursorPos;
 419
 420   // lock the mouse
 421   mouseLock();
 422
 423   //set the drag var
 424   mDragHit = true;
 425
 426   //let the parent get the event
 427   setFirstResponder();
 428}
 429
 430void GuiTextEditCtrl::onMouseDragged( const GuiEvent &event )
 431{
 432   S32 pos = calculateCursorPos( event.mousePoint );
 433
 434   // if the position is to the left
 435   if ( pos == -1 )
 436      mScrollDir = -1;
 437   else if ( pos == -2 ) // the position is to the right
 438      mScrollDir = 1;
 439   else // set the new cursor position
 440   {
 441      mScrollDir = 0;
 442      mCursorPos = pos;
 443   }
 444
 445   // update the block:
 446   mBlockStart = getMin( mCursorPos, mMouseDragStart );
 447   mBlockEnd = getMax( mCursorPos, mMouseDragStart );
 448   if ( mBlockStart < 0 )
 449      mBlockStart = 0;
 450
 451   if ( mBlockStart == mBlockEnd )
 452      mBlockStart = mBlockEnd = 0;
 453
 454   //let the parent get the event
 455   Parent::onMouseDragged(event);
 456}
 457
 458void GuiTextEditCtrl::onMouseUp(const GuiEvent &event)
 459{
 460   TORQUE_UNUSED(event);
 461   mDragHit = false;
 462   mScrollDir = 0;
 463
 464   mMouseUpTime = Platform::getRealMilliseconds();
 465   mouseUnlock();
 466}
 467
 468void GuiTextEditCtrl::saveUndoState()
 469{
 470   //save the current state
 471   mUndoText.set(&mTextBuffer);
 472   mUndoBlockStart = mBlockStart;
 473   mUndoBlockEnd   = mBlockEnd;
 474   mUndoCursorPos  = mCursorPos;
 475}
 476
 477void GuiTextEditCtrl::onCopy(bool andCut)
 478{
 479   // Don't copy/cut password field!
 480   if(mPasswordText)
 481      return;
 482
 483   if (mBlockEnd > 0)
 484   {
 485      //save the current state
 486      saveUndoState();
 487
 488      //copy the text to the clipboard
 489      UTF8* clipBuff = mTextBuffer.createSubstring8(mBlockStart, mBlockEnd - mBlockStart);
 490      Platform::setClipboard(clipBuff);
 491      delete[] clipBuff;
 492
 493      //if we pressed the cut shortcut, we need to cut the selected text from the control...
 494      if (andCut)
 495      {
 496         mTextBuffer.cut(mBlockStart, mBlockEnd - mBlockStart);
 497         mCursorPos = mBlockStart;
 498      }
 499
 500      mBlockStart = 0;
 501      mBlockEnd = 0;
 502   }
 503
 504}
 505
 506void GuiTextEditCtrl::onPaste()
 507{           
 508   //first, make sure there's something in the clipboard to copy...
 509   const UTF8 *clipboard = Platform::getClipboard();
 510   if(dStrlen(clipboard) <= 0)
 511      return;
 512
 513   //save the current state
 514   saveUndoState();
 515
 516   //delete anything hilited
 517   if (mBlockEnd > 0)
 518   {
 519      mTextBuffer.cut(mBlockStart, mBlockEnd - mBlockStart);
 520      mCursorPos = mBlockStart;
 521      mBlockStart = 0;
 522      mBlockEnd = 0;
 523   }
 524
 525   // We'll be converting to UTF16, and maybe trimming the string,
 526   // so let's use a StringBuffer, for convinience.
 527   StringBuffer pasteText(clipboard);
 528
 529   // Space left after we remove the highlighted text
 530   S32 stringLen = mTextBuffer.length();
 531
 532   // Trim down to fit in a buffer of size mMaxStrLen
 533   S32 pasteLen = pasteText.length();
 534
 535   if(stringLen + pasteLen > mMaxStrLen)
 536   {
 537      pasteLen = mMaxStrLen - stringLen;
 538
 539      pasteText.cut(pasteLen, pasteText.length() - pasteLen);
 540   }
 541
 542   if (mCursorPos == stringLen)
 543   {
 544      mTextBuffer.append(pasteText);
 545   }
 546   else
 547   {
 548      mTextBuffer.insert(mCursorPos, pasteText);
 549   }
 550
 551   mCursorPos += pasteLen;
 552}
 553
 554void GuiTextEditCtrl::onUndo()
 555{
 556    StringBuffer tempBuffer;
 557    S32 tempBlockStart;
 558    S32 tempBlockEnd;
 559    S32 tempCursorPos;
 560
 561    //save the current
 562    tempBuffer.set(&mTextBuffer);
 563    tempBlockStart = mBlockStart;
 564    tempBlockEnd   = mBlockEnd;
 565    tempCursorPos  = mCursorPos;
 566
 567    //restore the prev
 568    mTextBuffer.set(&mUndoText);
 569    mBlockStart = mUndoBlockStart;
 570    mBlockEnd   = mUndoBlockEnd;
 571    mCursorPos  = mUndoCursorPos;
 572
 573    //update the undo
 574    mUndoText.set(&tempBuffer);
 575    mUndoBlockStart = tempBlockStart;
 576    mUndoBlockEnd   = tempBlockEnd;
 577    mUndoCursorPos  = tempCursorPos;
 578}
 579
 580bool GuiTextEditCtrl::onKeyDown(const GuiEvent &event)
 581{
 582   if ( !isActive() || !isAwake() )
 583      return false;
 584
 585   S32 stringLen = mTextBuffer.length();
 586   setUpdate();
 587
 588   // Ugly, but now I'm cool like MarkF.
 589   if(event.keyCode == KEY_BACKSPACE)
 590      goto dealWithBackspace;
 591   
 592   if ( event.modifier & SI_SHIFT )
 593   {
 594
 595      // Added support for word jump selection.
 596
 597      if ( event.modifier & SI_CTRL )
 598      {
 599         switch ( event.keyCode )
 600         {
 601            case KEY_LEFT:
 602            {
 603               S32 newpos = findPrevWord();               
 604
 605               if ( mBlockStart == mBlockEnd )
 606               {
 607                  // There was not already a selection so start a new one.
 608                  mBlockStart = newpos;
 609                  mBlockEnd = mCursorPos;
 610               }
 611               else
 612               {
 613                  // There was a selection already...
 614                  // In this case the cursor MUST be at either the
 615                  // start or end of that selection.
 616
 617                  if ( mCursorPos == mBlockStart )
 618                  {
 619                     // We are at the start block and traveling left so
 620                     // just extend the start block farther left.                     
 621                     mBlockStart = newpos;
 622                  }
 623                  else
 624                  {
 625                     // We are at the end block BUT traveling left
 626                     // back towards the start block...
 627
 628                     if ( newpos > mBlockStart )
 629                     {
 630                        // We haven't overpassed the existing start block
 631                        // so just trim back the end block.
 632                        mBlockEnd = newpos;
 633                     }
 634                     else if ( newpos == mBlockStart )
 635                     {
 636                        // We are back at the start, so no more selection.
 637                        mBlockEnd = mBlockStart = 0;
 638                     }
 639                     else
 640                     {
 641                        // Only other option, we just backtracked PAST
 642                        // our original start block.
 643                        // So the new position becomes the start block
 644                        // and the old start block becomes the end block.
 645                        mBlockEnd = mBlockStart;
 646                        mBlockStart = newpos;
 647                     }
 648                  }
 649               }
 650                              
 651               mCursorPos = newpos;
 652
 653               return true;
 654            }
 655
 656            case KEY_RIGHT:
 657            {
 658               S32 newpos = findNextWord();               
 659
 660               if ( mBlockStart == mBlockEnd )
 661               {
 662                  // There was not already a selection so start a new one.
 663                  mBlockStart = mCursorPos;
 664                  mBlockEnd = newpos;
 665               }
 666               else
 667               {
 668                  // There was a selection already...
 669                  // In this case the cursor MUST be at either the
 670                  // start or end of that selection.
 671
 672                  if ( mCursorPos == mBlockEnd )
 673                  {
 674                     // We are at the end block and traveling right so
 675                     // just extend the end block farther right.                     
 676                     mBlockEnd = newpos;
 677                  }
 678                  else
 679                  {
 680                     // We are at the start block BUT traveling right
 681                     // back towards the end block...
 682
 683                     if ( newpos < mBlockEnd )
 684                     {
 685                        // We haven't overpassed the existing end block
 686                        // so just trim back the start block.
 687                        mBlockStart = newpos;
 688                     }
 689                     else if ( newpos == mBlockEnd )
 690                     {
 691                        // We are back at the end, so no more selection.
 692                        mBlockEnd = mBlockStart = 0;
 693                     }
 694                     else
 695                     {
 696                        // Only other option, we just backtracked PAST
 697                        // our original end block.
 698                        // So the new position becomes the end block
 699                        // and the old end block becomes the start block.
 700                        mBlockStart = mBlockEnd;
 701                        mBlockEnd = newpos;
 702                     }
 703                  }
 704               }
 705
 706               mCursorPos = newpos;
 707
 708               return true;
 709            }
 710            
 711            default:
 712               break;
 713         }
 714      }
 715
 716      // End support for word jump selection.
 717
 718
 719        switch ( event.keyCode )
 720        {
 721            case KEY_TAB:
 722               if ( mTabComplete )
 723               {
 724              onTabComplete_callback("1");
 725                  return true;
 726               }
 727            break; // We don't want to fall through if we don't handle the TAB here.
 728
 729            case KEY_HOME:
 730               mBlockStart = 0;
 731               mBlockEnd = mCursorPos;
 732               mCursorPos = 0;
 733               return true;
 734
 735            case KEY_END:
 736                mBlockStart = mCursorPos;
 737                mBlockEnd = stringLen;
 738                mCursorPos = stringLen;
 739                return true;
 740
 741            case KEY_LEFT:
 742                if ((mCursorPos > 0) & (stringLen > 0))
 743                {
 744                    //if we already have a selected block
 745                    if (mCursorPos == mBlockEnd)
 746                    {
 747                        mCursorPos--;
 748                        mBlockEnd--;
 749                        if (mBlockEnd == mBlockStart)
 750                        {
 751                            mBlockStart = 0;
 752                            mBlockEnd = 0;
 753                        }
 754                    }
 755                    else {
 756                        mCursorPos--;
 757                        mBlockStart = mCursorPos;
 758
 759                        if (mBlockEnd == 0)
 760                        {
 761                            mBlockEnd = mCursorPos + 1;
 762                        }
 763                    }
 764                }
 765                return true;
 766
 767            case KEY_RIGHT:
 768                if (mCursorPos < stringLen)
 769                {
 770                    if ((mCursorPos == mBlockStart) && (mBlockEnd > 0))
 771                    {
 772                        mCursorPos++;
 773                        mBlockStart++;
 774                        if (mBlockStart == mBlockEnd)
 775                        {
 776                            mBlockStart = 0;
 777                            mBlockEnd = 0;
 778                        }
 779                    }
 780                    else
 781                    {
 782                        if (mBlockEnd == 0)
 783                        {
 784                            mBlockStart = mCursorPos;
 785                            mBlockEnd = mCursorPos;
 786                        }
 787                        mCursorPos++;
 788                        mBlockEnd++;
 789                    }
 790                }
 791                return true;
 792
 793            case KEY_RETURN:
 794            case KEY_NUMPADENTER:
 795           
 796               return dealWithEnter(false);
 797
 798            default:
 799               break;
 800        }
 801    }
 802   else if (event.modifier & SI_CTRL)
 803   {
 804      switch(event.keyCode)
 805      {
 806#if defined(TORQUE_OS_MAC)
 807         // Added UNIX emacs key bindings - just a little hack here...
 808
 809         // Ctrl-B - move one character back
 810         case KEY_B:
 811         { 
 812            GuiEvent new_event;
 813            new_event.modifier = 0;
 814            new_event.keyCode = KEY_LEFT;
 815            return(onKeyDown(new_event));
 816         }
 817
 818         // Ctrl-F - move one character forward
 819         case KEY_F:
 820         { 
 821            GuiEvent new_event;
 822            new_event.modifier = 0;
 823            new_event.keyCode = KEY_RIGHT;
 824            return(onKeyDown(new_event));
 825         }
 826
 827         // Ctrl-A - move to the beginning of the line
 828         case KEY_A:
 829         { 
 830            GuiEvent new_event;
 831            new_event.modifier = 0;
 832            new_event.keyCode = KEY_HOME;
 833            return(onKeyDown(new_event));
 834         }
 835
 836         // Ctrl-E - move to the end of the line
 837         case KEY_E:
 838         { 
 839            GuiEvent new_event;
 840            new_event.modifier = 0;
 841            new_event.keyCode = KEY_END;
 842            return(onKeyDown(new_event));
 843         }
 844
 845         // Ctrl-P - move backward in history
 846         case KEY_P:
 847         { 
 848            GuiEvent new_event;
 849            new_event.modifier = 0;
 850            new_event.keyCode = KEY_UP;
 851            return(onKeyDown(new_event));
 852         }
 853
 854         // Ctrl-N - move forward in history
 855         case KEY_N:
 856         { 
 857            GuiEvent new_event;
 858            new_event.modifier = 0;
 859            new_event.keyCode = KEY_DOWN;
 860            return(onKeyDown(new_event));
 861         }
 862
 863         // Ctrl-D - delete under cursor
 864         case KEY_D:
 865         { 
 866            GuiEvent new_event;
 867            new_event.modifier = 0;
 868            new_event.keyCode = KEY_DELETE;
 869            return(onKeyDown(new_event));
 870         }
 871
 872         case KEY_U:
 873         { 
 874            GuiEvent new_event;
 875            new_event.modifier = SI_CTRL;
 876            new_event.keyCode = KEY_DELETE;
 877            return(onKeyDown(new_event));
 878         }
 879
 880         // End added UNIX emacs key bindings
 881#endif
 882
 883         // Adding word jump navigation.
 884
 885         case KEY_LEFT:
 886         {
 887
 888            mCursorPos = findPrevWord();
 889            mBlockStart = 0;
 890            mBlockEnd = 0;
 891            return true;
 892         }
 893
 894         case KEY_RIGHT:
 895         {
 896            mCursorPos = findNextWord();
 897            mBlockStart = 0;
 898            mBlockEnd = 0;
 899            return true;
 900         }         
 901         
 902#if !defined(TORQUE_OS_MAC)
 903         // Select all
 904         case KEY_A:
 905         {
 906            selectAllText();
 907            return true;
 908         }
 909
 910         // windows style cut / copy / paste / undo keybinds
 911         case KEY_C:
 912         case KEY_X:
 913         {
 914            // copy, and cut the text if we hit ctrl-x
 915            onCopy( event.keyCode==<a href="/coding/group/group__input__constants/#group__input__constants_1ggabe97be4d441d7e2653e24933583bb2eba480a807305121d41673b8c208898f497">KEY_X</a> );
 916            return true;
 917         }
 918         case KEY_V:
 919         {
 920            onPaste();
 921
 922            // Execute the console command!
 923            execConsoleCallback();
 924            return true;
 925         }
 926
 927         case KEY_Z:
 928            if (! mDragHit)
 929            {
 930               onUndo();
 931               return true;
 932            }
 933#endif
 934
 935         case KEY_DELETE:
 936         case KEY_BACKSPACE:
 937            //save the current state
 938            saveUndoState();
 939
 940            //delete everything in the field
 941            mTextBuffer.set("");
 942            mCursorPos  = 0;
 943            mBlockStart = 0;
 944            mBlockEnd   = 0;
 945
 946            execConsoleCallback();
 947
 948            return true;
 949         default:
 950            break;
 951      }
 952   }
 953#if defined(TORQUE_OS_MAC)
 954   // mac style cut / copy / paste / undo keybinds
 955   else if (event.modifier & SI_ALT)
 956   {
 957      // Mac command key maps to alt in torque.
 958
 959      // Added Mac cut/copy/paste/undo keys
 960      switch(event.keyCode)
 961      {
 962         // Select all
 963         case KEY_A:
 964         {
 965            selectAllText();
 966            return true;
 967         }
 968         case KEY_C:
 969         case KEY_X:
 970         {
 971            // copy, and cut the text if we hit cmd-x
 972            onCopy( event.keyCode==<a href="/coding/group/group__input__constants/#group__input__constants_1ggabe97be4d441d7e2653e24933583bb2eba480a807305121d41673b8c208898f497">KEY_X</a> );
 973            return true;
 974         }
 975         case KEY_V:
 976         {
 977            onPaste();
 978
 979            // Execute the console command!
 980            execConsoleCallback();
 981
 982            return true;
 983         }
 984            
 985         case KEY_Z:
 986            if (! mDragHit)
 987            {
 988               onUndo();
 989               return true;
 990            }
 991            
 992         default:
 993            break;
 994      }
 995   }
 996#endif
 997   else
 998   {
 999      switch(event.keyCode)
1000      {
1001         case KEY_ESCAPE:
1002            if( mEscapeCommand.isNotEmpty() )
1003            {
1004               evaluate( mEscapeCommand );
1005               return( true );
1006            }
1007            return( Parent::onKeyDown( event ) );
1008
1009         case KEY_RETURN:
1010         case KEY_NUMPADENTER:
1011           
1012            return dealWithEnter(true);
1013
1014         case KEY_UP:
1015         {
1016            if( mHistorySize > 0 )
1017            {
1018               if(mHistoryDirty)
1019               {
1020                  updateHistory(&mTextBuffer, false);
1021                  mHistoryDirty = false;
1022               }
1023
1024               mHistoryIndex--;
1025               
1026               if(mHistoryIndex >= 0 && mHistoryIndex <= mHistoryLast)
1027                  setText(mHistoryBuf[mHistoryIndex]);
1028               else if(mHistoryIndex < 0)
1029                  mHistoryIndex = 0;
1030            }
1031               
1032            return true;
1033         }
1034
1035         case KEY_DOWN:
1036         {
1037            if( mHistorySize > 0 )
1038            {
1039               if(mHistoryDirty)
1040               {
1041                  updateHistory(&mTextBuffer, false);
1042                  mHistoryDirty = false;
1043               }
1044               mHistoryIndex++;
1045               if(mHistoryIndex > mHistoryLast)
1046               {
1047                  mHistoryIndex = mHistoryLast + 1;
1048                  setText("");
1049               }
1050               else
1051                  setText(mHistoryBuf[mHistoryIndex]);
1052            }
1053            return true;
1054         }
1055
1056         case KEY_LEFT:
1057            
1058            // If we have a selection put the cursor to the left side of it.
1059            if ( mBlockStart != mBlockEnd )
1060            {
1061               mCursorPos = mBlockStart;
1062               mBlockStart = mBlockEnd = 0;
1063            }
1064            else
1065            {
1066               mBlockStart = mBlockEnd = 0;
1067               mCursorPos = getMax( mCursorPos - 1, 0 );               
1068            }
1069
1070            return true;
1071
1072         case KEY_RIGHT:
1073
1074            // If we have a selection put the cursor to the right side of it.            
1075            if ( mBlockStart != mBlockEnd )
1076            {
1077               mCursorPos = mBlockEnd;
1078               mBlockStart = mBlockEnd = 0;
1079            }
1080            else
1081            {
1082               mBlockStart = mBlockEnd = 0;
1083               mCursorPos = getMin( mCursorPos + 1, stringLen );               
1084            }
1085
1086            return true;
1087
1088         case KEY_BACKSPACE:
1089dealWithBackspace:
1090            //save the current state
1091            saveUndoState();
1092
1093            if (mBlockEnd > 0)
1094            {
1095               mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart);
1096               mCursorPos  = mBlockStart;
1097               mBlockStart = 0;
1098               mBlockEnd   = 0;
1099               mHistoryDirty = true;
1100
1101               // Execute the console command!
1102               execConsoleCallback();
1103
1104            }
1105            else if (mCursorPos > 0)
1106            {
1107               mTextBuffer.cut(mCursorPos-1, 1);
1108               mCursorPos--;
1109               mHistoryDirty = true;
1110
1111               // Execute the console command!
1112               execConsoleCallback();
1113            }
1114            return true;
1115
1116         case KEY_DELETE:
1117            //save the current state
1118            saveUndoState();
1119
1120            if (mBlockEnd > 0)
1121            {
1122               mHistoryDirty = true;
1123               mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart);
1124
1125               mCursorPos = mBlockStart;
1126               mBlockStart = 0;
1127               mBlockEnd = 0;
1128
1129               // Execute the console command!
1130               execConsoleCallback();
1131            }
1132            else if (mCursorPos < stringLen)
1133            {
1134               mHistoryDirty = true;
1135               mTextBuffer.cut(mCursorPos, 1);
1136
1137               // Execute the console command!
1138               execConsoleCallback();
1139            }
1140            return true;
1141
1142         case KEY_INSERT:
1143            mInsertOn = !mInsertOn;
1144            return true;
1145
1146         case KEY_HOME:
1147            mBlockStart = 0;
1148            mBlockEnd   = 0;
1149            mCursorPos  = 0;
1150            return true;
1151
1152         case KEY_END:
1153            mBlockStart = 0;
1154            mBlockEnd   = 0;
1155            mCursorPos  = stringLen;
1156            return true;
1157      
1158         default:
1159            break;
1160
1161         }
1162   }
1163
1164   switch ( event.keyCode )
1165   {
1166      case KEY_TAB:
1167         if ( mTabComplete )
1168         {
1169         onTabComplete_callback("0");
1170            return( true );
1171         }
1172      case KEY_UP:
1173      case KEY_DOWN:
1174      case KEY_ESCAPE:
1175         return Parent::onKeyDown( event );
1176      default:
1177         break;
1178   }
1179         
1180   // Handle character input events.
1181
1182   if( mProfile->mFont->isValidChar( event.ascii ) )
1183   {
1184      handleCharInput( event.ascii );
1185      return true;
1186   }
1187
1188   // Or eat it if that's appropriate.
1189   if( mSinkAllKeyEvents )
1190      return true;
1191
1192   // Not handled - pass the event to it's parent.
1193   return Parent::onKeyDown( event );
1194}
1195
1196bool GuiTextEditCtrl::dealWithEnter( bool clearResponder )
1197{
1198   //first validate
1199   if (mProfile->mReturnTab)
1200   {
1201      onLoseFirstResponder();
1202   }
1203
1204   updateHistory(&mTextBuffer, true);
1205   mHistoryDirty = false;
1206
1207   //next exec the alt console command
1208   execAltConsoleCallback();
1209
1210   // Notify of Return
1211   onReturn_callback();
1212
1213   if (mProfile->mReturnTab)
1214   {
1215      GuiCanvas *root = getRoot();
1216      if (root)
1217      {
1218         root->tabNext();
1219         return true;
1220      }
1221   }
1222   
1223   if( clearResponder )
1224      clearFirstResponder();
1225
1226   return true;
1227}
1228
1229void GuiTextEditCtrl::setFirstResponder()
1230{
1231   Parent::setFirstResponder();
1232
1233   GuiCanvas *root = getRoot();
1234   if (root != NULL)
1235   {
1236      root->enableKeyboardTranslation();
1237  
1238
1239      // If the native OS accelerator keys are not disabled
1240      // then some key events like Delete, ctrl+V, etc may
1241      // not make it down to us.
1242      root->setNativeAcceleratorsEnabled( false );
1243   }
1244}
1245
1246void GuiTextEditCtrl::onLoseFirstResponder()
1247{
1248   GuiCanvas *root = getRoot();
1249   if( root )
1250   {
1251    root->setNativeAcceleratorsEnabled( true );
1252    root->disableKeyboardTranslation();
1253   }
1254
1255   updateHistory(&mTextBuffer, true);
1256   mHistoryDirty = false;
1257
1258   //execute the validate command
1259   if( mValidateCommand.isNotEmpty() )
1260      evaluate( mValidateCommand.c_str() );
1261
1262   onValidate_callback();
1263
1264   // Redraw the control:
1265   setUpdate();
1266
1267   // Lost Responder
1268   Parent::onLoseFirstResponder();
1269}
1270
1271void GuiTextEditCtrl::onRender( Point2I offset, const RectI &updateRect )
1272{
1273   RectI ctrlRect( offset, getExtent() );
1274
1275   //if opaque, fill the update rect with the fill color
1276   if ( mProfile->mOpaque )
1277   {
1278      if ( !mTextValid )
1279         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
1280      else if ( isFirstResponder() )
1281         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorHL );
1282      else
1283         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColor );
1284   }
1285
1286   //if there's a border, draw the border
1287   if ( mProfile->mBorder )
1288   {
1289      renderBorder( ctrlRect, mProfile );
1290      if ( !mTextValid )
1291         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
1292   }
1293
1294   drawText( ctrlRect, isFirstResponder() );
1295}
1296
1297void GuiTextEditCtrl::onPreRender()
1298{
1299   if ( isFirstResponder() )
1300   {
1301      U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;
1302      mNumFramesElapsed++;
1303      if ( ( timeElapsed > 500 ) && ( mNumFramesElapsed > 3 ) )
1304      {
1305         mCursorOn = !mCursorOn;
1306         mTimeLastCursorFlipped = Platform::getVirtualMilliseconds();
1307         mNumFramesElapsed = 0;
1308         setUpdate();
1309      }
1310
1311      //update the cursor if the text is scrolling
1312      if ( mDragHit )
1313      {
1314         if ( ( mScrollDir < 0 ) && ( mCursorPos > 0 ) )
1315            mCursorPos--;
1316         else if ( ( mScrollDir > 0 ) && ( mCursorPos < (S32) mTextBuffer.length() ) )
1317            mCursorPos++;
1318      }
1319   }
1320}
1321
1322void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused )
1323{
1324   StringBuffer textBuffer;
1325   Point2I drawPoint = drawRect.point;
1326   Point2I paddingLeftTop, paddingRightBottom;
1327
1328   // Or else just copy it over.
1329   char *renderText = Con::getReturnBuffer( GuiTextEditCtrl::MAX_STRING_LENGTH );
1330   getRenderText( renderText );
1331
1332   // Apply password masking (make the masking char optional perhaps?)
1333   if(mPasswordText)
1334   {
1335      const U32 renderLen = dStrlen( renderText );
1336      for( U32 i = 0; i < renderLen; i++ )
1337         textBuffer.append(mPasswordMask);
1338   }
1339   else
1340   {
1341       textBuffer.set( renderText );
1342   }
1343
1344   bool usePlaceholder = false;
1345   if (textBuffer.length() == 0 && !isFocused)
1346   {
1347      textBuffer.set(mPlaceholderText);
1348      usePlaceholder = true;
1349   }
1350
1351   // Just a little sanity.
1352   if(mCursorPos > textBuffer.length()) 
1353      mCursorPos = textBuffer.length();
1354
1355   paddingLeftTop.set(( mProfile->mTextOffset.x != 0 ? mProfile->mTextOffset.x : 3 ), mProfile->mTextOffset.y);
1356   paddingRightBottom = paddingLeftTop;
1357
1358   // Center vertically:
1359   drawPoint.y += ( ( drawRect.extent.y - paddingLeftTop.y - paddingRightBottom.y - S32( mProfile->mFont->getHeight() ) ) / 2 ) + paddingLeftTop.y;
1360
1361   // Align horizontally:
1362   
1363   S32 textWidth = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), textBuffer.length());
1364
1365   switch( mProfile->mAlignment )
1366   {
1367   case GuiControlProfile::RightJustify:
1368      drawPoint.x += ( drawRect.extent.x - textWidth - paddingRightBottom.x );
1369      break;
1370   case GuiControlProfile::CenterJustify:
1371      drawPoint.x += ( ( drawRect.extent.x - textWidth ) / 2 );
1372      break;
1373   default:
1374   case GuiControlProfile::LeftJustify :
1375      drawPoint.x += paddingLeftTop.x;
1376      break;
1377   }
1378
1379   ColorI fontColor = mActive ? mProfile->mFontColor : mProfile->mFontColorNA;
1380
1381   if (usePlaceholder)
1382      fontColor = mProfile->mFontColorNA;
1383
1384   // now draw the text
1385   Point2I cursorStart, cursorEnd;
1386   mTextOffset.y = drawPoint.y;
1387   mTextOffset.x = drawPoint.x;
1388
1389   if ( drawRect.extent.x - paddingLeftTop.x > textWidth )
1390      mTextOffset.x = drawPoint.x;
1391   else
1392   {
1393      // Alignment affects large text
1394      if ( mProfile->mAlignment == GuiControlProfile::RightJustify
1395         || mProfile->mAlignment == GuiControlProfile::CenterJustify )
1396      {
1397         if ( mTextOffset.x + textWidth < (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x)
1398            mTextOffset.x = (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x - textWidth;
1399      }
1400   }
1401
1402   // calculate the cursor
1403   if( isFocused && mActive )
1404   {
1405      // Where in the string are we?
1406      S32 cursorOffset=0, charWidth=0;
1407      UTF16 tempChar = textBuffer.getChar(mCursorPos);
1408
1409      // Alright, we want to terminate things momentarily.
1410      if(mCursorPos > 0)
1411      {
1412         cursorOffset = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), mCursorPos);
1413      }
1414      else
1415         cursorOffset = 0;
1416
1417      if( tempChar && mProfile->mFont->isValidChar( tempChar ) )
1418         charWidth = mProfile->mFont->getCharWidth( tempChar );
1419      else
1420         charWidth = paddingRightBottom.x;
1421
1422      if( mTextOffset.x + cursorOffset + 1 >= (drawRect.point.x + drawRect.extent.x) ) // +1 is for the cursor width
1423      {
1424         // Cursor somewhere beyond the textcontrol,
1425         // skip forward roughly 25% of the total width (if possible)
1426         S32 skipForward = drawRect.extent.x / 4 * 3;
1427
1428         if ( cursorOffset + skipForward > textWidth )
1429            mTextOffset.x = (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x - textWidth;
1430         else
1431         {
1432            //mTextOffset.x -= skipForward;
1433            S32 mul = (S32)( mFloor( (cursorOffset-drawRect.extent.x) / skipForward ) );
1434            mTextOffset.x -= skipForward * mul + drawRect.extent.x - 1; // -1 is for the cursor width
1435         }
1436      }
1437      else if( mTextOffset.x + cursorOffset < drawRect.point.x + paddingLeftTop.x )
1438      {
1439         // Cursor somewhere before the textcontrol
1440         // skip backward roughly 25% of the total width (if possible)
1441         S32 skipBackward = drawRect.extent.x / 4 * 3;
1442
1443         if ( cursorOffset - skipBackward < 0 )
1444            mTextOffset.x = drawRect.point.x + paddingLeftTop.x;
1445         else
1446         {
1447            S32 mul = (S32)( mFloor( cursorOffset / skipBackward ) );
1448            mTextOffset.x += drawRect.point.x - mTextOffset.x - skipBackward * mul;
1449         }
1450      }
1451      cursorStart.x = mTextOffset.x + cursorOffset;
1452
1453#ifdef TORQUE_OS_MAC
1454      cursorStart.x += charWidth/2;
1455#endif
1456      
1457      cursorEnd.x = cursorStart.x;
1458
1459      S32 cursorHeight = mProfile->mFont->getHeight();
1460      if ( cursorHeight < drawRect.extent.y )
1461      {
1462         cursorStart.y = drawPoint.y;
1463         cursorEnd.y = cursorStart.y + cursorHeight;
1464      }
1465      else
1466      {
1467         cursorStart.y = drawRect.point.y;
1468         cursorEnd.y = cursorStart.y + drawRect.extent.y;
1469      }
1470   }
1471
1472   //draw the text
1473   if ( !isFocused )
1474      mBlockStart = mBlockEnd = 0;
1475
1476   //also verify the block start/end
1477   if ((mBlockStart > textBuffer.length() || (mBlockEnd > textBuffer.length()) || (mBlockStart > mBlockEnd)))
1478      mBlockStart = mBlockEnd = 0;
1479
1480   Point2I tempOffset = mTextOffset;
1481
1482   //draw the portion before the highlight
1483   if ( mBlockStart > 0 )
1484   {
1485      GFX->getDrawUtil()->setBitmapModulation( fontColor );
1486      const UTF16* preString2 = textBuffer.getPtr();
1487      GFX->getDrawUtil()->drawText( mProfile->mFont, tempOffset, preString2, mProfile->mFontColors );
1488      tempOffset.x += mProfile->mFont->getStrNWidth(preString2, mBlockStart);
1489   }
1490
1491   //draw the highlighted portion
1492   if ( mBlockEnd > 0 )
1493   {
1494      const UTF16* highlightBuff = textBuffer.getPtr() + mBlockStart;
1495      U32 highlightBuffLen = mBlockEnd-mBlockStart;
1496
1497      S32 highlightWidth = mProfile->mFont->getStrNWidth(highlightBuff, highlightBuffLen);
1498
1499      GFX->getDrawUtil()->drawRectFill( Point2I( tempOffset.x, drawRect.point.y ),
1500         Point2I( tempOffset.x + highlightWidth, drawRect.point.y + drawRect.extent.y - 1),
1501         mProfile->mFontColorSEL );
1502
1503      GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColorHL );
1504      GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, highlightBuff, highlightBuffLen, mProfile->mFontColors );
1505      tempOffset.x += highlightWidth;
1506   }
1507
1508   //draw the portion after the highlight
1509   if(mBlockEnd < textBuffer.length())
1510   {
1511      const UTF16* finalBuff = textBuffer.getPtr() + mBlockEnd;
1512      U32 finalBuffLen = textBuffer.length() - mBlockEnd;
1513
1514      GFX->getDrawUtil()->setBitmapModulation( fontColor );
1515      GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, finalBuff, finalBuffLen, mProfile->mFontColors );
1516   }
1517
1518   //draw the cursor
1519   if ( isFocused && mCursorOn )
1520      GFX->getDrawUtil()->drawLine( cursorStart, cursorEnd, mProfile->mCursorColor );
1521}
1522
1523bool GuiTextEditCtrl::hasText()
1524{
1525   return ( mTextBuffer.length() );
1526}
1527
1528void GuiTextEditCtrl::invalidText(bool playSound)
1529{
1530   mTextValid = false;
1531
1532   if ( playSound )
1533      playDeniedSound();
1534}
1535
1536void GuiTextEditCtrl::validText()
1537{
1538   mTextValid = true;
1539}
1540
1541bool GuiTextEditCtrl::isValidText()
1542{
1543   return mTextValid;
1544}
1545
1546void GuiTextEditCtrl::playDeniedSound()
1547{
1548   if ( mDeniedSound )
1549      SFX->playOnce( mDeniedSound );
1550}
1551
1552const char *GuiTextEditCtrl::getScriptValue()
1553{
1554   return StringTable->insert(mTextBuffer.getPtr8());
1555}
1556
1557void GuiTextEditCtrl::setScriptValue(const char *value)
1558{
1559   mTextBuffer.set(value);
1560   mCursorPos = mTextBuffer.length();
1561}
1562
1563void GuiTextEditCtrl::handleCharInput( U16 ascii )
1564{
1565   S32 stringLen = mTextBuffer.length();
1566
1567   // Get the character ready to add to a UTF8 string.
1568   UTF16 convertedChar[2] = { ascii, 0 };
1569
1570   //see if it's a number field
1571   if ( mProfile->mNumbersOnly )
1572   {
1573      if (ascii == '-')
1574      {
1575         //a minus sign only exists at the beginning, and only a single minus sign
1576         if (mCursorPos != 0 && !isAllTextSelected())
1577         {
1578            invalidText();
1579            return;
1580         }
1581
1582         if (mInsertOn && (mTextBuffer.getChar(0) == '-'))
1583         {
1584            invalidText();
1585            return;
1586         }
1587      }
1588      // BJTODO: This is probably not unicode safe.
1589      else if (ascii != '.' && (ascii < '0' || ascii > '9'))
1590      {
1591         invalidText();
1592         return;
1593      }
1594      else
1595         validText();
1596   }
1597
1598   //save the current state
1599   saveUndoState();
1600
1601   bool alreadyCut = false;
1602
1603   //delete anything highlighted
1604   if ( mBlockEnd > 0 )
1605   {
1606      mTextBuffer.cut(mBlockStart, mBlockEnd-mBlockStart);
1607      mCursorPos  = mBlockStart;
1608      mBlockStart = 0;
1609      mBlockEnd   = 0;
1610
1611      // We just changed the string length!
1612      // Get its new value.
1613      stringLen = mTextBuffer.length();
1614
1615      // If we already had text highlighted, we just want to cut that text.
1616      // Don't cut the next character even if insert is not on.
1617      alreadyCut = true;
1618   }
1619
1620   if ( ( mInsertOn && ( stringLen < mMaxStrLen ) ) ||
1621      ( !mInsertOn && ( mCursorPos < mMaxStrLen ) ) )
1622   {
1623      if ( mCursorPos == stringLen )
1624      {
1625         mTextBuffer.append(convertedChar);
1626         mCursorPos++;
1627      }
1628      else
1629      {
1630         if ( mInsertOn || alreadyCut )
1631         {
1632            mTextBuffer.insert(mCursorPos, convertedChar);
1633            mCursorPos++;
1634         }
1635         else
1636         {
1637            mTextBuffer.cut(mCursorPos, 1);
1638            mTextBuffer.insert(mCursorPos, convertedChar);
1639            mCursorPos++;
1640         }
1641      }
1642   }
1643   else
1644      playDeniedSound();
1645
1646   //reset the history index
1647   mHistoryDirty = true;
1648
1649   //execute the console command if it exists
1650   execConsoleCallback();
1651}
1652
1653S32 GuiTextEditCtrl::findPrevWord()
1654{   
1655   // First the first word to the left of the current cursor position 
1656   // and return the positional index of its starting character.
1657
1658   // We define the first character of a word as any non-whitespace
1659   // character which has a non-alpha-numeric character to its immediate left.
1660
1661   const UTF8* text = mTextBuffer.getPtr8();
1662
1663   for ( S32 i = mCursorPos - 1; i > 0; i-- )
1664   {  
1665      if ( !dIsspace( text[i] ) )
1666      {
1667         if ( !dIsalnum( text[i-1] ) )
1668         {
1669            return i;
1670         }
1671      }
1672   }
1673
1674   return 0;
1675}
1676
1677S32 GuiTextEditCtrl::findNextWord()
1678{
1679   // First the first word to the right of the current cursor position 
1680   // and return the positional index of its starting character.
1681
1682   // We define the first character of a word as any non-whitespace
1683   // character which has a non-alpha-numeric character to its immediate left.
1684   
1685   const UTF8* text = mTextBuffer.getPtr8();
1686
1687   for ( S32 i = mCursorPos + 1; i < mTextBuffer.length(); i++ )
1688   {  
1689      if ( !dIsspace( text[i] ) )
1690      {
1691         if ( !dIsalnum( text[i-1] ) )
1692         {
1693            return i;
1694         }
1695      }
1696   }
1697
1698   return mTextBuffer.length();
1699}
1700
1701DefineEngineMethod( GuiTextEditCtrl, getText, const char*, (),,
1702   "@brief Acquires the current text displayed in this control.\n\n"
1703   "@tsexample\n"
1704   "// Acquire the value of the text control.\n"
1705   "%text = %thisGuiTextEditCtrl.getText();\n"
1706   "@endtsexample\n\n"
1707   "@return The current text within the control.\n\n"
1708   "@see GuiControl")
1709{
1710   if( !object->hasText() )
1711      return StringTable->EmptyString();
1712
1713   char *retBuffer = Con::getReturnBuffer( GuiTextEditCtrl::MAX_STRING_LENGTH );
1714   object->getText( retBuffer );
1715
1716   return retBuffer;
1717}
1718
1719DefineEngineMethod( GuiTextEditCtrl, setText, void, (const char* text),,
1720   "@brief Sets the text in the control.\n\n"
1721   "@param text Text to place in the control.\n"
1722   "@tsexample\n"
1723   "// Define the text to display\n"
1724   "%text = \"Text!\"\n\n"
1725   "// Inform the GuiTextEditCtrl to display the defined text\n"
1726   "%thisGuiTextEditCtrl.setText(%text);\n"
1727   "@endtsexample\n\n"
1728   "@see GuiControl")
1729{
1730   object->setText( text );
1731}
1732
1733DefineEngineMethod( GuiTextEditCtrl, getCursorPos, S32, (),,
1734   "@brief Returns the current position of the text cursor in the control.\n\n"
1735   "@tsexample\n"
1736   "// Acquire the cursor position in the control\n"
1737   "%position = %thisGuiTextEditCtrl.getCursorPost();\n"
1738   "@endtsexample\n\n"
1739   "@return Text cursor position within the control.\n\n"
1740   "@see GuiControl")
1741{
1742   return( object->getCursorPos() );
1743}
1744
1745DefineEngineMethod( GuiTextEditCtrl, setCursorPos, void, (S32 position),,
1746   "@brief Sets the text cursor at the defined position within the control.\n\n"
1747   "@param position Text position to set the text cursor.\n"
1748   "@tsexample\n"
1749   "// Define the cursor position\n"
1750   "%position = \"12\";\n\n"
1751   "// Inform the GuiTextEditCtrl control to place the text cursor at the defined position\n"
1752   "%thisGuiTextEditCtrl.setCursorPos(%position);\n"
1753   "@endtsexample\n\n"
1754   "@see GuiControl")
1755{
1756   object->setCursorPos( position );
1757}
1758
1759DefineEngineMethod( GuiTextEditCtrl, isAllTextSelected, bool, (),,
1760   "@brief Checks to see if all text in the control has been selected.\n\n"
1761   "@tsexample\n"
1762   "// Check to see if all text has been selected or not.\n"
1763   "%allSelected = %thisGuiTextEditCtrl.isAllTextSelected();\n"
1764   "@endtsexample\n\n"
1765   "@return True if all text in the control is selected, otherwise false.\n\n"
1766   "@see GuiControl")
1767{
1768   return object->isAllTextSelected();
1769}
1770
1771DefineEngineMethod( GuiTextEditCtrl, selectAllText, void, (),,
1772   "@brief Selects all text within the control.\n\n"
1773   "@tsexample\n"
1774   "// Inform the control to select all of its text.\n"
1775   "%thisGuiTextEditCtrl.selectAllText();\n"
1776   "@endtsexample\n\n"
1777   "@see GuiControl")
1778{
1779   object->selectAllText();
1780}
1781
1782DefineEngineMethod( GuiTextEditCtrl, clearSelectedText, void, (),,
1783   "@brief Unselects all selected text in the control.\n\n"
1784   "@tsexample\n"
1785   "// Inform the control to unselect all of its selected text\n"
1786   "%thisGuiTextEditCtrl.clearSelectedText();\n"
1787   "@endtsexample\n\n"
1788   "@see GuiControl")
1789{
1790   object->clearSelectedText();
1791}
1792
1793DefineEngineMethod( GuiTextEditCtrl, forceValidateText, void, (),,
1794   "@brief Force a validation to occur.\n\n"
1795   "@tsexample\n"
1796   "// Inform the control to force a validation of its text.\n"
1797   "%thisGuiTextEditCtrl.forceValidateText();\n"
1798   "@endtsexample\n\n"
1799   "@see GuiControl")
1800{
1801   object->forceValidateText();
1802}
1803
1804DefineEngineMethod(GuiTextEditCtrl, invalidText, void, (bool playSound), (true),
1805   "@brief Trigger the invalid sound and make the box red.nn"
1806   "@param playSound Play the invalid text sound or not.n")
1807{
1808   object->invalidText(playSound);
1809}
1810
1811
1812DefineEngineMethod(GuiTextEditCtrl, validText, void, (), ,
1813   "@brief Restores the box to normal color.nn")
1814{
1815   object->validText();
1816}
1817
1818DefineEngineMethod(GuiTextEditCtrl, isValidText, bool, (), ,
1819   "@brief Returns if the text is set to valid or not.n"
1820   "@Return true if text is set to valid, false if not.nn")
1821{
1822   return object->isValidText();
1823}
1824