InputField.cs 122 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294
  1. using System;
  2. using System.Collections;
  3. using UnityEngine.Events;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.Serialization;
  6. #if UNITY_EDITOR
  7. using UnityEditor;
  8. #endif
  9. namespace UnityEngine.UI
  10. {
  11. /// <summary>
  12. /// Turn a simple label into a interactable input field.
  13. /// </summary>
  14. [AddComponentMenu("UI/Input Field", 31)]
  15. public class InputField
  16. : Selectable,
  17. IUpdateSelectedHandler,
  18. IBeginDragHandler,
  19. IDragHandler,
  20. IEndDragHandler,
  21. IPointerClickHandler,
  22. ISubmitHandler,
  23. ICanvasElement,
  24. ILayoutElement
  25. {
  26. /// <summary>
  27. /// Setting the content type acts as a shortcut for setting a combination of InputType, CharacterValidation, LineType, and TouchScreenKeyboardType
  28. /// </summary>
  29. /// <remarks>
  30. /// The ContentType affects character validation, keyboard type used (on platforms with on-screen keyboards), whether the InputField accepts multiple lines, and whether the text is autocorrected (on platforms that offer input auto-correction) or is treated as a password where the characters are not shown directly.
  31. /// </remarks>
  32. public enum ContentType
  33. {
  34. /// <summary>
  35. /// Allows all input.
  36. /// </summary>
  37. Standard,
  38. /// <summary>
  39. /// Allows all input and performs auto-correction on platforms that support it.
  40. /// </summary>
  41. Autocorrected,
  42. /// <summary>
  43. /// Allow whole numbers (positive or negative).
  44. /// </summary>
  45. IntegerNumber,
  46. /// <summary>
  47. /// Allows decimal numbers (positive or negative).
  48. /// </summary>
  49. DecimalNumber,
  50. /// <summary>
  51. /// Allows letters A-Z, a-z and numbers 0-9.
  52. /// </summary>
  53. Alphanumeric,
  54. /// <summary>
  55. /// The InputField is used for typing in a name, and enforces capitalization of the first letter of each word. Note that the user can circumvent the first letter capitalization rules by deleting automatically-capitalized letters.
  56. /// </summary>
  57. Name,
  58. /// <summary>
  59. /// The input is used for typing in an email address.
  60. /// </summary>
  61. EmailAddress,
  62. /// <summary>
  63. /// Allows all input and hides the typed characters by showing them as asterisks characters.
  64. /// </summary>
  65. Password,
  66. /// <summary>
  67. /// Allows integer numbers and hides the typed characters by showing them as asterisks characters.
  68. /// </summary>
  69. Pin,
  70. /// <summary>
  71. /// Custom types that allows user-defined settings.
  72. /// </summary>
  73. Custom
  74. }
  75. /// <summary>
  76. /// Type of data expected by the input field mobile keyboard.
  77. /// </summary>
  78. public enum InputType
  79. {
  80. /// <summary>
  81. /// The standard mobile keyboard
  82. /// </summary>
  83. Standard,
  84. /// <summary>
  85. /// The mobile autocorrect keyboard.
  86. /// </summary>
  87. AutoCorrect,
  88. /// <summary>
  89. /// The mobile password keyboard.
  90. /// </summary>
  91. Password,
  92. }
  93. /// <summary>
  94. /// The type of characters that are allowed to be added to the string.
  95. /// </summary>
  96. /// <remarks>
  97. /// Note that the character validation does not validate the entire string as being valid or not. It only does validation on a per-character level, resulting in the typed character either being added to the string or not
  98. /// </remarks>
  99. public enum CharacterValidation
  100. {
  101. /// <summary>
  102. /// No validation. Any input is valid.
  103. /// </summary>
  104. None,
  105. /// <summary>
  106. /// Allow whole numbers (positive or negative).
  107. /// Characters 0-9 and - (dash / minus sign) are allowed. The dash is only allowed as the first character.
  108. /// </summary>
  109. Integer,
  110. /// <summary>
  111. /// Allows decimal numbers (positive or negative).
  112. /// </summary>
  113. /// <remarks>
  114. /// Characters 0-9, . (dot), and - (dash / minus sign) are allowed. The dash is only allowed as the first character. Only one dot in the string is allowed.
  115. /// </remarks>
  116. Decimal,
  117. /// <summary>
  118. /// Allows letters A-Z, a-z and numbers 0-9.
  119. /// </summary>
  120. Alphanumeric,
  121. /// <summary>
  122. /// Only allow names and enforces capitalization.
  123. /// </summary>
  124. /// <remarks>
  125. /// Allows letters, spaces, and ' (apostrophe). A character after a space is automatically made upper case. A character not after a space is automatically made lowercase. A character after an apostrophe can be either upper or lower case. Only one apostrophe in the string is allowed. More than one space in a row is not allowed.
  126. ///
  127. /// A characters is considered a letter if it is categorized as a Unicode letter, as implemented by the Char.Isletter method in .Net.
  128. /// </remarks>
  129. Name,
  130. /// <summary>
  131. /// Allows the characters that are allowed in an email address.
  132. /// </summary>
  133. /// <remarks>
  134. /// Allows characters A-Z, a.z, 0-9, @, . (dot), !, #, $, %, &amp;, ', *, +, -, /, =, ?, ^, _, `, {, |, }, and ~.
  135. ///
  136. /// Only one @ is allowed in the string and more than one dot in a row are not allowed. Note that the character validation does not validate the entire string as being a valid email address since it only does validation on a per-character level, resulting in the typed character either being added to the string or not.
  137. /// </remarks>
  138. EmailAddress
  139. }
  140. /// <summary>
  141. /// The LineType is used to describe the behavior of the InputField.
  142. /// </summary>
  143. public enum LineType
  144. {
  145. /// <summary>
  146. /// Only allows 1 line to be entered. Has horizontal scrolling and no word wrap. Pressing enter will submit the InputField.
  147. /// </summary>
  148. SingleLine,
  149. /// <summary>
  150. /// Is a multiline InputField with vertical scrolling and overflow. Pressing the return key will submit.
  151. /// </summary>
  152. MultiLineSubmit,
  153. /// <summary>
  154. /// Is a multiline InputField with vertical scrolling and overflow. Pressing the return key will insert a new line character.
  155. /// </summary>
  156. MultiLineNewline
  157. }
  158. public delegate char OnValidateInput(string text, int charIndex, char addedChar);
  159. [Serializable]
  160. /// <summary>
  161. /// Unity Event with a inputfield as a param.
  162. /// </summary>
  163. public class SubmitEvent : UnityEvent<string> {}
  164. [Serializable]
  165. /// <summary>
  166. /// The callback sent anytime the Inputfield is updated.
  167. /// </summary>
  168. public class OnChangeEvent : UnityEvent<string> {}
  169. protected TouchScreenKeyboard m_Keyboard;
  170. static private readonly char[] kSeparators = { ' ', '.', ',', '\t', '\r', '\n' };
  171. /// <summary>
  172. /// Text Text used to display the input's value.
  173. /// </summary>
  174. [SerializeField]
  175. [FormerlySerializedAs("text")]
  176. protected Text m_TextComponent;
  177. [SerializeField]
  178. protected Graphic m_Placeholder;
  179. [SerializeField]
  180. private ContentType m_ContentType = ContentType.Standard;
  181. [FormerlySerializedAs("inputType")]
  182. [SerializeField]
  183. private InputType m_InputType = InputType.Standard;
  184. [FormerlySerializedAs("asteriskChar")]
  185. [SerializeField]
  186. private char m_AsteriskChar = '*';
  187. [FormerlySerializedAs("keyboardType")]
  188. [SerializeField]
  189. private TouchScreenKeyboardType m_KeyboardType = TouchScreenKeyboardType.Default;
  190. [SerializeField]
  191. private LineType m_LineType = LineType.SingleLine;
  192. [FormerlySerializedAs("hideMobileInput")]
  193. [SerializeField]
  194. private bool m_HideMobileInput = false;
  195. [FormerlySerializedAs("validation")]
  196. [SerializeField]
  197. private CharacterValidation m_CharacterValidation = CharacterValidation.None;
  198. [FormerlySerializedAs("characterLimit")]
  199. [SerializeField]
  200. private int m_CharacterLimit = 0;
  201. [FormerlySerializedAs("onSubmit")]
  202. [FormerlySerializedAs("m_OnSubmit")]
  203. [FormerlySerializedAs("m_EndEdit")]
  204. [SerializeField]
  205. private SubmitEvent m_OnEndEdit = new SubmitEvent();
  206. [FormerlySerializedAs("onValueChange")]
  207. [FormerlySerializedAs("m_OnValueChange")]
  208. [SerializeField]
  209. private OnChangeEvent m_OnValueChanged = new OnChangeEvent();
  210. [FormerlySerializedAs("onValidateInput")]
  211. [SerializeField]
  212. private OnValidateInput m_OnValidateInput;
  213. [FormerlySerializedAs("selectionColor")]
  214. [SerializeField]
  215. private Color m_CaretColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
  216. [SerializeField]
  217. private bool m_CustomCaretColor = false;
  218. [SerializeField]
  219. private Color m_SelectionColor = new Color(168f / 255f, 206f / 255f, 255f / 255f, 192f / 255f);
  220. [SerializeField]
  221. [FormerlySerializedAs("mValue")]
  222. protected string m_Text = string.Empty;
  223. [SerializeField]
  224. [Range(0f, 4f)]
  225. private float m_CaretBlinkRate = 0.85f;
  226. [SerializeField]
  227. [Range(1, 5)]
  228. private int m_CaretWidth = 1;
  229. [SerializeField]
  230. private bool m_ReadOnly = false;
  231. [SerializeField]
  232. private bool m_ShouldActivateOnSelect = true;
  233. protected int m_CaretPosition = 0;
  234. protected int m_CaretSelectPosition = 0;
  235. private RectTransform caretRectTrans = null;
  236. protected UIVertex[] m_CursorVerts = null;
  237. private TextGenerator m_InputTextCache;
  238. private CanvasRenderer m_CachedInputRenderer;
  239. private bool m_PreventFontCallback = false;
  240. [NonSerialized] protected Mesh m_Mesh;
  241. private bool m_AllowInput = false;
  242. private bool m_ShouldActivateNextUpdate = false;
  243. private bool m_UpdateDrag = false;
  244. private bool m_DragPositionOutOfBounds = false;
  245. private const float kHScrollSpeed = 0.05f;
  246. private const float kVScrollSpeed = 0.10f;
  247. protected bool m_CaretVisible;
  248. private Coroutine m_BlinkCoroutine = null;
  249. private float m_BlinkStartTime = 0.0f;
  250. protected int m_DrawStart = 0;
  251. protected int m_DrawEnd = 0;
  252. private Coroutine m_DragCoroutine = null;
  253. private string m_OriginalText = "";
  254. private bool m_WasCanceled = false;
  255. private bool m_HasDoneFocusTransition = false;
  256. private WaitForSecondsRealtime m_WaitForSecondsRealtime;
  257. private bool m_TouchKeyboardAllowsInPlaceEditing = false;
  258. private BaseInput input
  259. {
  260. get
  261. {
  262. if (EventSystem.current && EventSystem.current.currentInputModule)
  263. return EventSystem.current.currentInputModule.input;
  264. return null;
  265. }
  266. }
  267. private string compositionString
  268. {
  269. get { return input != null ? input.compositionString : Input.compositionString; }
  270. }
  271. // Doesn't include dot and @ on purpose! See usage for details.
  272. const string kEmailSpecialCharacters = "!#$%&'*+-/=?^_`{|}~";
  273. protected InputField()
  274. {
  275. EnforceTextHOverflow();
  276. }
  277. protected Mesh mesh
  278. {
  279. get
  280. {
  281. if (m_Mesh == null)
  282. m_Mesh = new Mesh();
  283. return m_Mesh;
  284. }
  285. }
  286. protected TextGenerator cachedInputTextGenerator
  287. {
  288. get
  289. {
  290. if (m_InputTextCache == null)
  291. m_InputTextCache = new TextGenerator();
  292. return m_InputTextCache;
  293. }
  294. }
  295. /// <summary>
  296. /// Should the mobile keyboard input be hidden. This allows for input to happen with a caret in the InputField instead of a OS input box above the keyboard.
  297. /// </summary>
  298. /// <example>
  299. /// <code>
  300. /// using UnityEngine;
  301. /// using System.Collections;
  302. /// using UnityEngine.UI; // Required when Using UI elements.
  303. ///
  304. /// public class Example : MonoBehaviour
  305. /// {
  306. /// public InputField mainInputField;
  307. ///
  308. /// public void Start()
  309. /// {
  310. /// //This setting can be toggled in the inspector.
  311. /// mainInputField.shouldHideMobileInput = true;
  312. /// }
  313. /// }
  314. /// </code>
  315. /// </example>
  316. public bool shouldHideMobileInput
  317. {
  318. set
  319. {
  320. SetPropertyUtility.SetStruct(ref m_HideMobileInput, value);
  321. }
  322. get
  323. {
  324. switch (Application.platform)
  325. {
  326. case RuntimePlatform.Android:
  327. case RuntimePlatform.IPhonePlayer:
  328. case RuntimePlatform.tvOS:
  329. return m_HideMobileInput;
  330. }
  331. return true;
  332. }
  333. }
  334. /// <summary>
  335. /// Should the inputfield be automatically activated upon selection.
  336. /// </summary>
  337. public virtual bool shouldActivateOnSelect
  338. {
  339. set
  340. {
  341. m_ShouldActivateOnSelect = value;
  342. }
  343. get
  344. {
  345. return m_ShouldActivateOnSelect && Application.platform != RuntimePlatform.tvOS;
  346. }
  347. }
  348. /// <summary>
  349. /// Input field's current text value. This is not necessarily the same as what is visible on screen.
  350. /// </summary>
  351. /// <remarks>
  352. /// Note that null is invalid value for InputField.text.
  353. /// </remarks>
  354. /// <example>
  355. /// <code>
  356. /// using UnityEngine;
  357. /// using System.Collections;
  358. /// using UnityEngine.UI; // Required when Using UI elements.
  359. ///
  360. /// public class Example : MonoBehaviour
  361. /// {
  362. /// public InputField mainInputField;
  363. ///
  364. /// public void Start()
  365. /// {
  366. /// mainInputField.text = "Enter Text Here...";
  367. /// }
  368. /// }
  369. /// </code>
  370. /// </example>
  371. public string text
  372. {
  373. get
  374. {
  375. return m_Text;
  376. }
  377. set
  378. {
  379. SetText(value);
  380. }
  381. }
  382. /// <summary>
  383. /// Set the current text value of the Input field without invoking onValueChanged.
  384. /// </summary>
  385. /// <remarks>
  386. /// This is not necessarily the same as what is visible on screen.
  387. /// </remarks>
  388. public void SetTextWithoutNotify(string input)
  389. {
  390. SetText(input, false);
  391. }
  392. void SetText(string value, bool sendCallback = true)
  393. {
  394. if (this.text == value)
  395. return;
  396. if (value == null)
  397. value = "";
  398. value = value.Replace("\0", string.Empty); // remove embedded nulls
  399. if (m_LineType == LineType.SingleLine)
  400. value = value.Replace("\n", "").Replace("\t", "");
  401. // If we have an input validator, validate the input and apply the character limit at the same time.
  402. if (onValidateInput != null || characterValidation != CharacterValidation.None)
  403. {
  404. m_Text = "";
  405. OnValidateInput validatorMethod = onValidateInput ?? Validate;
  406. m_CaretPosition = m_CaretSelectPosition = value.Length;
  407. int charactersToCheck = characterLimit > 0 ? Math.Min(characterLimit, value.Length) : value.Length;
  408. for (int i = 0; i < charactersToCheck; ++i)
  409. {
  410. char c = validatorMethod(m_Text, m_Text.Length, value[i]);
  411. if (c != 0)
  412. m_Text += c;
  413. }
  414. }
  415. else
  416. {
  417. m_Text = characterLimit > 0 && value.Length > characterLimit ? value.Substring(0, characterLimit) : value;
  418. }
  419. #if UNITY_EDITOR
  420. if (!Application.isPlaying)
  421. {
  422. SendOnValueChangedAndUpdateLabel();
  423. return;
  424. }
  425. #endif
  426. if (m_Keyboard != null)
  427. m_Keyboard.text = m_Text;
  428. if (m_CaretPosition > m_Text.Length)
  429. m_CaretPosition = m_CaretSelectPosition = m_Text.Length;
  430. else if (m_CaretSelectPosition > m_Text.Length)
  431. m_CaretSelectPosition = m_Text.Length;
  432. if (sendCallback)
  433. SendOnValueChanged();
  434. UpdateLabel();
  435. }
  436. /// <summary>
  437. /// Whether the InputField has focus and whether it is able to process events.
  438. /// </summary>
  439. /// <example>
  440. /// <code>
  441. /// using UnityEngine;
  442. /// using System.Collections;
  443. /// using UnityEngine.UI; // Required when Using UI elements.
  444. ///
  445. /// public class Example : MonoBehaviour
  446. /// {
  447. /// public GameObject mainInputField;
  448. ///
  449. /// void Update()
  450. /// {
  451. /// //If the input field is focused, change its color to green.
  452. /// if (mainInputField.GetComponent<InputField>().isFocused == true)
  453. /// {
  454. /// mainInputField.GetComponent<Image>().color = Color.green;
  455. /// }
  456. /// }
  457. /// }
  458. /// </code>
  459. /// </example>
  460. public bool isFocused
  461. {
  462. get { return m_AllowInput; }
  463. }
  464. /// <summary>
  465. /// The blinking rate of the input caret, defined as the number of times the blink cycle occurs per second.
  466. /// </summary>
  467. public float caretBlinkRate
  468. {
  469. get { return m_CaretBlinkRate; }
  470. set
  471. {
  472. if (SetPropertyUtility.SetStruct(ref m_CaretBlinkRate, value))
  473. {
  474. if (m_AllowInput)
  475. SetCaretActive();
  476. }
  477. }
  478. }
  479. /// <summary>
  480. /// The width of the caret in pixels.
  481. /// </summary>
  482. public int caretWidth { get { return m_CaretWidth; } set { if (SetPropertyUtility.SetStruct(ref m_CaretWidth, value)) MarkGeometryAsDirty(); } }
  483. /// <summary>
  484. /// The Text component that is going to be used to render the text to screen.
  485. /// </summary>
  486. public Text textComponent
  487. {
  488. get { return m_TextComponent; }
  489. set
  490. {
  491. if (m_TextComponent != null)
  492. {
  493. m_TextComponent.UnregisterDirtyVerticesCallback(MarkGeometryAsDirty);
  494. m_TextComponent.UnregisterDirtyVerticesCallback(UpdateLabel);
  495. m_TextComponent.UnregisterDirtyMaterialCallback(UpdateCaretMaterial);
  496. }
  497. if (SetPropertyUtility.SetClass(ref m_TextComponent, value))
  498. {
  499. EnforceTextHOverflow();
  500. if (m_TextComponent != null)
  501. {
  502. m_TextComponent.RegisterDirtyVerticesCallback(MarkGeometryAsDirty);
  503. m_TextComponent.RegisterDirtyVerticesCallback(UpdateLabel);
  504. m_TextComponent.RegisterDirtyMaterialCallback(UpdateCaretMaterial);
  505. }
  506. }
  507. }
  508. }
  509. /// <summary>
  510. /// This is an optional ‘empty’ graphic to show that the InputField text field is empty. Note that this ‘empty' graphic still displays even when the InputField is selected (that is; when there is focus on it).
  511. /// A placeholder graphic can be used to show subtle hints or make it more obvious that the control is an InputField.
  512. /// </summary>
  513. /// <remarks>
  514. /// If a Text component is used as the placeholder, it's recommended to make the placeholder text look different from the real text of the InputField so they are not easily confused. For example, the placeholder text might be a more subtle color or have lower alpha value.
  515. /// </remarks>
  516. public Graphic placeholder { get { return m_Placeholder; } set { SetPropertyUtility.SetClass(ref m_Placeholder, value); } }
  517. /// <summary>
  518. /// The custom caret color used if customCaretColor is set.
  519. /// </summary>
  520. public Color caretColor { get { return customCaretColor ? m_CaretColor : textComponent.color; } set { if (SetPropertyUtility.SetColor(ref m_CaretColor, value)) MarkGeometryAsDirty(); } }
  521. /// <summary>
  522. /// Should a custom caret color be used or should the textComponent.color be used.
  523. /// </summary>
  524. public bool customCaretColor { get { return m_CustomCaretColor; } set { if (m_CustomCaretColor != value) { m_CustomCaretColor = value; MarkGeometryAsDirty(); } } }
  525. /// <summary>
  526. /// The color of the highlight to show which characters are selected.
  527. /// </summary>
  528. /// <example>
  529. /// <code>
  530. /// using UnityEngine;
  531. /// using System.Collections;
  532. /// using UnityEngine.UI; // Required when Using UI elements.
  533. ///
  534. /// public class Example : MonoBehaviour
  535. /// {
  536. /// public InputField mainInputField;
  537. ///
  538. /// // Changes the color of the highlight that shows what characters are selected.
  539. /// void ChangeSelectionColor()
  540. /// {
  541. /// mainInputField.selectionColor = Color.red;
  542. /// }
  543. /// }
  544. /// </code>
  545. /// </example>
  546. public Color selectionColor { get { return m_SelectionColor; } set { if (SetPropertyUtility.SetColor(ref m_SelectionColor, value)) MarkGeometryAsDirty(); } }
  547. /// <summary>
  548. /// The Unity Event to call when editing has ended
  549. /// </summary>
  550. /// <example>
  551. /// <code>
  552. /// using UnityEngine;
  553. /// using System.Collections;
  554. /// using UnityEngine.UI; // Required when Using UI elements.
  555. ///
  556. /// public class Example : MonoBehaviour
  557. /// {
  558. /// public InputField mainInputField;
  559. ///
  560. /// // Checks if there is anything entered into the input field.
  561. /// void LockInput(InputField input)
  562. /// {
  563. /// if (input.text.Length > 0)
  564. /// {
  565. /// Debug.Log("Text has been entered");
  566. /// }
  567. /// else if (input.text.Length == 0)
  568. /// {
  569. /// Debug.Log("Main Input Empty");
  570. /// }
  571. /// }
  572. ///
  573. /// public void Start()
  574. /// {
  575. /// //Adds a listener that invokes the "LockInput" method when the player finishes editing the main input field.
  576. /// //Passes the main input field into the method when "LockInput" is invoked
  577. /// mainInputField.onEndEdit.AddListener(delegate {LockInput(mainInputField); });
  578. /// }
  579. /// }
  580. /// </code>
  581. /// </example>
  582. public SubmitEvent onEndEdit { get { return m_OnEndEdit; } set { SetPropertyUtility.SetClass(ref m_OnEndEdit, value); } }
  583. [Obsolete("onValueChange has been renamed to onValueChanged")]
  584. public OnChangeEvent onValueChange { get { return onValueChanged; } set { onValueChanged = value; } }
  585. /// <summary>
  586. /// Accessor to the OnChangeEvent.
  587. /// </summary>
  588. /// <example>
  589. /// <code>
  590. /// using UnityEngine;
  591. /// using System.Collections;
  592. /// using UnityEngine.UI; // Required when Using UI elements.
  593. ///
  594. /// public class Example : MonoBehaviour
  595. /// {
  596. /// public InputField mainInputField;
  597. ///
  598. /// public void Start()
  599. /// {
  600. /// //Adds a listener to the main input field and invokes a method when the value changes.
  601. /// mainInputField.onValueChange.AddListener(delegate {ValueChangeCheck(); });
  602. /// }
  603. ///
  604. /// // Invoked when the value of the text field changes.
  605. /// public void ValueChangeCheck()
  606. /// {
  607. /// Debug.Log("Value Changed");
  608. /// }
  609. /// }
  610. /// </code>
  611. /// </example>
  612. public OnChangeEvent onValueChanged { get { return m_OnValueChanged; } set { SetPropertyUtility.SetClass(ref m_OnValueChanged, value); } }
  613. /// <summary>
  614. /// The function to call to validate the input characters.
  615. /// </summary>
  616. /// <example>
  617. /// <code>
  618. /// using UnityEngine;
  619. /// using System.Collections;
  620. /// using UnityEngine.UI; // Required when Using UI elements.
  621. ///
  622. /// public class Example : MonoBehaviour
  623. /// {
  624. /// public InputField mainInputField;
  625. ///
  626. /// public void Start()
  627. /// {
  628. /// // Sets the MyValidate method to invoke after the input field's default input validation invoke (default validation happens every time a character is entered into the text field.)
  629. /// mainInputField.onValidateInput += delegate(string input, int charIndex, char addedChar) { return MyValidate(addedChar); };
  630. /// }
  631. ///
  632. /// private char MyValidate(char charToValidate)
  633. /// {
  634. /// //Checks if a dollar sign is entered....
  635. /// if (charToValidate == '$')
  636. /// {
  637. /// // ... if it is change it to an empty character.
  638. /// charToValidate = '\0';
  639. /// }
  640. /// return charToValidate;
  641. /// }
  642. /// }
  643. /// </code>
  644. /// </example>
  645. public OnValidateInput onValidateInput { get { return m_OnValidateInput; } set { SetPropertyUtility.SetClass(ref m_OnValidateInput, value); } }
  646. /// <summary>
  647. /// How many characters the input field is limited to. 0 = infinite.
  648. /// </summary>
  649. /// <example>
  650. /// <code>
  651. /// using UnityEngine;
  652. /// using System.Collections;
  653. /// using UnityEngine.UI; // Required when Using UI elements.
  654. ///
  655. /// public class Example : MonoBehaviour
  656. /// {
  657. /// public InputField mainInputField;
  658. /// public string playerName;
  659. ///
  660. /// void Start()
  661. /// {
  662. /// //Changes the character limit in the main input field.
  663. /// mainInputField.characterLimit = playerName.Length;
  664. /// }
  665. /// }
  666. /// </code>
  667. /// </example>
  668. public int characterLimit
  669. {
  670. get { return m_CharacterLimit; }
  671. set
  672. {
  673. if (SetPropertyUtility.SetStruct(ref m_CharacterLimit, Math.Max(0, value)))
  674. {
  675. UpdateLabel();
  676. if (m_Keyboard != null)
  677. m_Keyboard.characterLimit = value;
  678. }
  679. }
  680. }
  681. /// <summary>
  682. /// Specifies the type of the input text content.
  683. /// </summary>
  684. /// <remarks>
  685. /// The ContentType affects character validation, keyboard type used (on platforms with on-screen keyboards), whether the InputField accepts multiple lines, and whether the text is autocorrected (on platforms that offer input auto-correction) or is treated as a password where the characters are not shown directly.
  686. /// </remarks>
  687. /// <example>
  688. /// <code>
  689. /// using UnityEngine;
  690. /// using System.Collections;
  691. /// using UnityEngine.UI; // Required when Using UI elements.
  692. ///
  693. /// public class Example : MonoBehaviour
  694. /// {
  695. /// public InputField mainInputField;
  696. /// public string playerName;
  697. ///
  698. /// void Start()
  699. /// {
  700. /// //Changes the character limit in the main input field.
  701. /// mainInputField.characterLimit = playerName.Length;
  702. /// }
  703. /// }
  704. /// </code>
  705. /// </example>
  706. public ContentType contentType { get { return m_ContentType; } set { if (SetPropertyUtility.SetStruct(ref m_ContentType, value)) EnforceContentType(); } }
  707. /// <summary>
  708. /// The LineType used by the InputField.
  709. /// </summary>
  710. /// <example>
  711. /// <code>
  712. /// using UnityEngine;
  713. /// using System.Collections;
  714. /// using UnityEngine.UI; // Required when Using UI elements.
  715. ///
  716. /// public class Example : MonoBehaviour
  717. /// {
  718. /// public GameObject mainInputField;
  719. ///
  720. /// //When you press a button, this method is called.
  721. /// public void ChangeInputField(int type)
  722. /// {
  723. /// if (type == 0)
  724. /// {
  725. /// //Change the input field to "Single Line" line type.
  726. /// mainInputField.GetComponent<InputField>().lineType = InputField.LineType.SingleLine;
  727. /// }
  728. /// else if (type == 1)
  729. /// {
  730. /// //Change the input field to "MultiLine Newline" line type.
  731. /// mainInputField.GetComponent<InputField>().lineType = InputField.LineType.MultiLineNewline;
  732. /// }
  733. /// else if (type == 2)
  734. /// {
  735. /// //Change the input field to "MultiLine Submit" line type.
  736. /// mainInputField.GetComponent<InputField>().lineType = InputField.LineType.MultiLineSubmit;
  737. /// }
  738. /// }
  739. /// }
  740. /// </code>
  741. /// </example>
  742. public LineType lineType
  743. {
  744. get { return m_LineType; }
  745. set
  746. {
  747. if (SetPropertyUtility.SetStruct(ref m_LineType, value))
  748. {
  749. SetToCustomIfContentTypeIsNot(ContentType.Standard, ContentType.Autocorrected);
  750. EnforceTextHOverflow();
  751. }
  752. }
  753. }
  754. /// <summary>
  755. /// The type of input expected. See InputField.InputType.
  756. /// </summary>
  757. public InputType inputType { get { return m_InputType; } set { if (SetPropertyUtility.SetStruct(ref m_InputType, value)) SetToCustom(); } }
  758. /// <summary>
  759. /// The TouchScreenKeyboard being used to edit the Input Field.
  760. /// </summary>
  761. public TouchScreenKeyboard touchScreenKeyboard { get { return m_Keyboard; } }
  762. /// <summary>
  763. /// They type of mobile keyboard that will be used.
  764. /// </summary>
  765. public TouchScreenKeyboardType keyboardType
  766. {
  767. get { return m_KeyboardType; }
  768. set
  769. {
  770. if (SetPropertyUtility.SetStruct(ref m_KeyboardType, value))
  771. SetToCustom();
  772. }
  773. }
  774. /// <summary>
  775. /// The type of validation to perform on a character
  776. /// </summary>
  777. public CharacterValidation characterValidation { get { return m_CharacterValidation; } set { if (SetPropertyUtility.SetStruct(ref m_CharacterValidation, value)) SetToCustom(); } }
  778. /// <summary>
  779. /// Set the InputField to be read only.
  780. /// </summary>
  781. /// <remarks>
  782. /// Setting read only allows for highlighting of text without allowing modifications via keyboard.
  783. /// </remarks>
  784. public bool readOnly { get { return m_ReadOnly; } set { m_ReadOnly = value; } }
  785. /// <summary>
  786. /// If the input field supports multiple lines.
  787. /// </summary>
  788. /// <example>
  789. /// <code>
  790. /// using UnityEngine;
  791. /// using System.Collections;
  792. /// using UnityEngine.UI; // Required when Using UI elements.
  793. ///
  794. /// public class Example : MonoBehaviour
  795. /// {
  796. /// public InputField mainInputField;
  797. ///
  798. /// public void Update()
  799. /// {
  800. /// //Check to see if the input field is set to allow multiple lines.
  801. /// if (mainInputField.multiLine)
  802. /// {
  803. /// //Set the input field to only allow Single Lines, if it is currently set to allow Multiple lines.
  804. /// mainInputField.lineType = InputField.LineType.SingleLine;
  805. /// //Print to console
  806. /// Debug.Log("The main input field is now set to allow single lines only!");
  807. /// }
  808. /// }
  809. /// }
  810. /// </code>
  811. /// </example>
  812. public bool multiLine { get { return m_LineType == LineType.MultiLineNewline || lineType == LineType.MultiLineSubmit; } }
  813. /// <summary>
  814. /// The character used to hide text in password field.
  815. /// </summary>
  816. /// <remarks>
  817. /// Not shown in the inspector.
  818. /// </remarks>
  819. /// <example>
  820. /// <code>
  821. /// using UnityEngine;
  822. /// using System.Collections;
  823. /// using UnityEngine.UI; // Required when Using UI elements.
  824. ///
  825. /// public class Example : MonoBehaviour
  826. /// {
  827. /// public InputField mainInputField;
  828. ///
  829. /// void Start()
  830. /// {
  831. /// // changes the password symbol. 0 = $, 1 = ! 2 = £ and so on.
  832. /// mainInputField.asteriskChar = "$!£%&*"[0];
  833. /// }
  834. /// }
  835. /// </code>
  836. /// </example>
  837. public char asteriskChar { get { return m_AsteriskChar; } set { if (SetPropertyUtility.SetStruct(ref m_AsteriskChar, value)) UpdateLabel(); } }
  838. /// <summary>
  839. /// If the InputField was canceled and will revert back to the original text upon DeactivateInputField.
  840. /// </summary>
  841. public bool wasCanceled { get { return m_WasCanceled; } }
  842. /// <summary>
  843. /// Clamp a value (by reference) between 0 and the current text length.
  844. /// </summary>
  845. /// <param name="pos">The input position to be clampped</param>
  846. protected void ClampPos(ref int pos)
  847. {
  848. if (pos < 0) pos = 0;
  849. else if (pos > text.Length) pos = text.Length;
  850. }
  851. /// <summary>
  852. /// Current position of the cursor.
  853. /// Getters are public Setters are protected
  854. /// </summary>
  855. protected int caretPositionInternal { get { return m_CaretPosition + compositionString.Length; } set { m_CaretPosition = value; ClampPos(ref m_CaretPosition); } }
  856. protected int caretSelectPositionInternal { get { return m_CaretSelectPosition + compositionString.Length; } set { m_CaretSelectPosition = value; ClampPos(ref m_CaretSelectPosition); } }
  857. private bool hasSelection { get { return caretPositionInternal != caretSelectPositionInternal; } }
  858. #if UNITY_EDITOR
  859. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  860. [Obsolete("caretSelectPosition has been deprecated. Use selectionFocusPosition instead (UnityUpgradable) -> selectionFocusPosition", true)]
  861. public int caretSelectPosition { get { return selectionFocusPosition; } protected set { selectionFocusPosition = value; } }
  862. #endif
  863. /// <summary>
  864. /// Get: Returns the focus position as thats the position that moves around even during selection.
  865. /// Set: Set both the anchor and focus position such that a selection doesn't happen
  866. /// </summary>
  867. public int caretPosition
  868. {
  869. get { return m_CaretSelectPosition + compositionString.Length; }
  870. set { selectionAnchorPosition = value; selectionFocusPosition = value; }
  871. }
  872. /// <summary>
  873. /// The beginning point of the selection.
  874. /// </summary>
  875. /// <remarks>
  876. /// When making a selection with a mouse, the anchor is where in the document the mouse button is initially pressed.
  877. /// Get: Returns the beginning position of selection
  878. /// Set: If Input.compositionString is 0 set the fixed position.
  879. /// </remarks>
  880. public int selectionAnchorPosition
  881. {
  882. get { return m_CaretPosition + compositionString.Length; }
  883. set
  884. {
  885. if (compositionString.Length != 0)
  886. return;
  887. m_CaretPosition = value;
  888. ClampPos(ref m_CaretPosition);
  889. }
  890. }
  891. /// <summary>
  892. /// The end point of the selection.
  893. /// </summary>
  894. /// <remarks>
  895. /// When making a selection with a mouse, the focus is where in the document the mouse button is released.
  896. /// Get: Returns the end position of selection
  897. /// Set: If Input.compositionString is 0 set the variable position.
  898. /// </remarks>
  899. public int selectionFocusPosition
  900. {
  901. get { return m_CaretSelectPosition + compositionString.Length; }
  902. set
  903. {
  904. if (compositionString.Length != 0)
  905. return;
  906. m_CaretSelectPosition = value;
  907. ClampPos(ref m_CaretSelectPosition);
  908. }
  909. }
  910. #if UNITY_EDITOR
  911. // Remember: This is NOT related to text validation!
  912. // This is Unity's own OnValidate method which is invoked when changing values in the Inspector.
  913. protected override void OnValidate()
  914. {
  915. base.OnValidate();
  916. EnforceContentType();
  917. EnforceTextHOverflow();
  918. m_CharacterLimit = Math.Max(0, m_CharacterLimit);
  919. //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
  920. if (!IsActive())
  921. return;
  922. // fix case 1040277
  923. ClampPos(ref m_CaretPosition);
  924. ClampPos(ref m_CaretSelectPosition);
  925. UpdateLabel();
  926. if (m_AllowInput)
  927. SetCaretActive();
  928. }
  929. #endif // if UNITY_EDITOR
  930. protected override void OnEnable()
  931. {
  932. base.OnEnable();
  933. if (m_Text == null)
  934. m_Text = string.Empty;
  935. m_DrawStart = 0;
  936. m_DrawEnd = m_Text.Length;
  937. // If we have a cached renderer then we had OnDisable called so just restore the material.
  938. if (m_CachedInputRenderer != null)
  939. m_CachedInputRenderer.SetMaterial(m_TextComponent.GetModifiedMaterial(Graphic.defaultGraphicMaterial), Texture2D.whiteTexture);
  940. if (m_TextComponent != null)
  941. {
  942. m_TextComponent.RegisterDirtyVerticesCallback(MarkGeometryAsDirty);
  943. m_TextComponent.RegisterDirtyVerticesCallback(UpdateLabel);
  944. m_TextComponent.RegisterDirtyMaterialCallback(UpdateCaretMaterial);
  945. UpdateLabel();
  946. }
  947. }
  948. protected override void OnDisable()
  949. {
  950. // the coroutine will be terminated, so this will ensure it restarts when we are next activated
  951. m_BlinkCoroutine = null;
  952. DeactivateInputField();
  953. if (m_TextComponent != null)
  954. {
  955. m_TextComponent.UnregisterDirtyVerticesCallback(MarkGeometryAsDirty);
  956. m_TextComponent.UnregisterDirtyVerticesCallback(UpdateLabel);
  957. m_TextComponent.UnregisterDirtyMaterialCallback(UpdateCaretMaterial);
  958. }
  959. CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
  960. // Clear needs to be called otherwise sync never happens as the object is disabled.
  961. if (m_CachedInputRenderer != null)
  962. m_CachedInputRenderer.Clear();
  963. if (m_Mesh != null)
  964. DestroyImmediate(m_Mesh);
  965. m_Mesh = null;
  966. base.OnDisable();
  967. }
  968. IEnumerator CaretBlink()
  969. {
  970. // Always ensure caret is initially visible since it can otherwise be confusing for a moment.
  971. m_CaretVisible = true;
  972. yield return null;
  973. while (isFocused && m_CaretBlinkRate > 0)
  974. {
  975. // the blink rate is expressed as a frequency
  976. float blinkPeriod = 1f / m_CaretBlinkRate;
  977. // the caret should be ON if we are in the first half of the blink period
  978. bool blinkState = (Time.unscaledTime - m_BlinkStartTime) % blinkPeriod < blinkPeriod / 2;
  979. if (m_CaretVisible != blinkState)
  980. {
  981. m_CaretVisible = blinkState;
  982. if (!hasSelection)
  983. MarkGeometryAsDirty();
  984. }
  985. // Then wait again.
  986. yield return null;
  987. }
  988. m_BlinkCoroutine = null;
  989. }
  990. void SetCaretVisible()
  991. {
  992. if (!m_AllowInput)
  993. return;
  994. m_CaretVisible = true;
  995. m_BlinkStartTime = Time.unscaledTime;
  996. SetCaretActive();
  997. }
  998. // SetCaretActive will not set the caret immediately visible - it will wait for the next time to blink.
  999. // However, it will handle things correctly if the blink speed changed from zero to non-zero or non-zero to zero.
  1000. void SetCaretActive()
  1001. {
  1002. if (!m_AllowInput)
  1003. return;
  1004. if (m_CaretBlinkRate > 0.0f)
  1005. {
  1006. if (m_BlinkCoroutine == null)
  1007. m_BlinkCoroutine = StartCoroutine(CaretBlink());
  1008. }
  1009. else
  1010. {
  1011. m_CaretVisible = true;
  1012. }
  1013. }
  1014. private void UpdateCaretMaterial()
  1015. {
  1016. if (m_TextComponent != null && m_CachedInputRenderer != null)
  1017. m_CachedInputRenderer.SetMaterial(m_TextComponent.GetModifiedMaterial(Graphic.defaultGraphicMaterial), Texture2D.whiteTexture);
  1018. }
  1019. /// <summary>
  1020. /// Focus the input field initializing properties.
  1021. /// </summary>
  1022. /// <remarks>
  1023. /// Handles what happens after a user selects an InputField. This is a protected property. To return the focus state use InputField.isFocused. To shift focus to another GameObject, use EventSystem.SetSelectedGameObject.
  1024. /// A common use of this is allowing the user to type once focussed. Another way is outputting a message when the user clicks on a field(often seen when creating passwords).
  1025. /// </remarks>
  1026. /// <example>
  1027. /// //Create an Input Field by going to __Create__>__UI__>__Input Field__. Attach this script to the Input Field GameObject
  1028. /// <code>
  1029. /// using UnityEngine;
  1030. /// using UnityEngine.UI;
  1031. ///
  1032. /// public class Example : MonoBehaviour
  1033. /// {
  1034. /// InputField m_InputField;
  1035. /// void Start()
  1036. /// {
  1037. /// //Fetch the Input Field component from the GameObject
  1038. /// m_InputField = GetComponent<InputField>();
  1039. /// }
  1040. ///
  1041. /// void Update()
  1042. /// {
  1043. /// //Check if the Input Field is in focus and able to alter
  1044. /// if (m_InputField.isFocused)
  1045. /// {
  1046. /// //Change the Color of the Input Field's Image to green
  1047. /// m_InputField.GetComponent<Image>().color = Color.green;
  1048. /// }
  1049. /// }
  1050. /// }
  1051. /// </code>
  1052. /// </example>
  1053. protected void OnFocus()
  1054. {
  1055. SelectAll();
  1056. }
  1057. /// <summary>
  1058. /// Highlight the whole InputField.
  1059. /// </summary>
  1060. /// <remarks>
  1061. /// Sets the caretPosition to the length of the text and caretSelectPos to 0.
  1062. /// </remarks>
  1063. protected void SelectAll()
  1064. {
  1065. caretPositionInternal = text.Length;
  1066. caretSelectPositionInternal = 0;
  1067. }
  1068. /// <summary>
  1069. /// Move the caret index to end of text.
  1070. /// </summary>
  1071. /// <param name="shift">Only move the selection position to facilate selection</param>
  1072. public void MoveTextEnd(bool shift)
  1073. {
  1074. int position = text.Length;
  1075. if (shift)
  1076. {
  1077. caretSelectPositionInternal = position;
  1078. }
  1079. else
  1080. {
  1081. caretPositionInternal = position;
  1082. caretSelectPositionInternal = caretPositionInternal;
  1083. }
  1084. UpdateLabel();
  1085. }
  1086. /// <summary>
  1087. /// Move the caret index to start of text.
  1088. /// </summary>
  1089. /// <param name="shift">Only move the selection position to facilate selection</param>
  1090. public void MoveTextStart(bool shift)
  1091. {
  1092. int position = 0;
  1093. if (shift)
  1094. {
  1095. caretSelectPositionInternal = position;
  1096. }
  1097. else
  1098. {
  1099. caretPositionInternal = position;
  1100. caretSelectPositionInternal = caretPositionInternal;
  1101. }
  1102. UpdateLabel();
  1103. }
  1104. static string clipboard
  1105. {
  1106. get
  1107. {
  1108. return GUIUtility.systemCopyBuffer;
  1109. }
  1110. set
  1111. {
  1112. GUIUtility.systemCopyBuffer = value;
  1113. }
  1114. }
  1115. // Returns true if the TouchScreenKeyboard should be used. On Android and Chrome OS, we only want to use the
  1116. // TouchScreenKeyboard if in-place editing is not allowed (i.e. when we do not have a hardware keyboard available).
  1117. private bool TouchScreenKeyboardShouldBeUsed()
  1118. {
  1119. RuntimePlatform platform = Application.platform;
  1120. switch (platform)
  1121. {
  1122. case RuntimePlatform.Android:
  1123. return !TouchScreenKeyboard.isInPlaceEditingAllowed;
  1124. default:
  1125. return TouchScreenKeyboard.isSupported;
  1126. }
  1127. }
  1128. private bool InPlaceEditing()
  1129. {
  1130. return !TouchScreenKeyboard.isSupported || m_TouchKeyboardAllowsInPlaceEditing;
  1131. }
  1132. // In-place editing can change state if a hardware keyboard becomes available or is hidden while the input field is activated.
  1133. // This currently only happens on Chrome OS devices (that support laptop and tablet mode).
  1134. private bool InPlaceEditingChanged()
  1135. {
  1136. return m_TouchKeyboardAllowsInPlaceEditing != TouchScreenKeyboard.isInPlaceEditingAllowed;
  1137. }
  1138. void UpdateCaretFromKeyboard()
  1139. {
  1140. var selectionRange = m_Keyboard.selection;
  1141. var selectionStart = selectionRange.start;
  1142. var selectionEnd = selectionRange.end;
  1143. var caretChanged = false;
  1144. if (caretPositionInternal != selectionStart)
  1145. {
  1146. caretChanged = true;
  1147. caretPositionInternal = selectionStart;
  1148. }
  1149. if (caretSelectPositionInternal != selectionEnd)
  1150. {
  1151. caretSelectPositionInternal = selectionEnd;
  1152. caretChanged = true;
  1153. }
  1154. if (caretChanged)
  1155. {
  1156. m_BlinkStartTime = Time.unscaledTime;
  1157. UpdateLabel();
  1158. }
  1159. }
  1160. /// <summary>
  1161. /// Update the text based on input.
  1162. /// </summary>
  1163. // TODO: Make LateUpdate a coroutine instead. Allows us to control the update to only be when the field is active.
  1164. protected virtual void LateUpdate()
  1165. {
  1166. // Only activate if we are not already activated.
  1167. if (m_ShouldActivateNextUpdate)
  1168. {
  1169. if (!isFocused)
  1170. {
  1171. ActivateInputFieldInternal();
  1172. m_ShouldActivateNextUpdate = false;
  1173. return;
  1174. }
  1175. // Reset as we are already activated.
  1176. m_ShouldActivateNextUpdate = false;
  1177. }
  1178. AssignPositioningIfNeeded();
  1179. // If the device's state changed in a way that affects whether we should use a touchscreen keyboard or not,
  1180. // then we make sure to clear all of the caret/highlight state visually and deactivate the input field.
  1181. if (isFocused && InPlaceEditingChanged())
  1182. {
  1183. if (m_CachedInputRenderer != null)
  1184. {
  1185. using (var helper = new VertexHelper())
  1186. helper.FillMesh(mesh);
  1187. m_CachedInputRenderer.SetMesh(mesh);
  1188. }
  1189. DeactivateInputField();
  1190. }
  1191. if (!isFocused || InPlaceEditing())
  1192. return;
  1193. if (m_Keyboard == null || m_Keyboard.status != TouchScreenKeyboard.Status.Visible)
  1194. {
  1195. if (m_Keyboard != null)
  1196. {
  1197. if (!m_ReadOnly)
  1198. text = m_Keyboard.text;
  1199. if (m_Keyboard.status == TouchScreenKeyboard.Status.Canceled)
  1200. m_WasCanceled = true;
  1201. }
  1202. OnDeselect(null);
  1203. return;
  1204. }
  1205. string val = m_Keyboard.text;
  1206. if (m_Text != val)
  1207. {
  1208. if (m_ReadOnly)
  1209. {
  1210. m_Keyboard.text = m_Text;
  1211. }
  1212. else
  1213. {
  1214. m_Text = "";
  1215. for (int i = 0; i < val.Length; ++i)
  1216. {
  1217. char c = val[i];
  1218. if (c == '\r' || (int)c == 3)
  1219. c = '\n';
  1220. if (onValidateInput != null)
  1221. c = onValidateInput(m_Text, m_Text.Length, c);
  1222. else if (characterValidation != CharacterValidation.None)
  1223. c = Validate(m_Text, m_Text.Length, c);
  1224. if (lineType == LineType.MultiLineSubmit && c == '\n')
  1225. {
  1226. m_Keyboard.text = m_Text;
  1227. OnDeselect(null);
  1228. return;
  1229. }
  1230. if (c != 0)
  1231. m_Text += c;
  1232. }
  1233. if (characterLimit > 0 && m_Text.Length > characterLimit)
  1234. m_Text = m_Text.Substring(0, characterLimit);
  1235. if (m_Keyboard.canGetSelection)
  1236. {
  1237. UpdateCaretFromKeyboard();
  1238. }
  1239. else
  1240. {
  1241. caretPositionInternal = caretSelectPositionInternal = m_Text.Length;
  1242. }
  1243. // Set keyboard text before updating label, as we might have changed it with validation
  1244. // and update label will take the old value from keyboard if we don't change it here
  1245. if (m_Text != val)
  1246. m_Keyboard.text = m_Text;
  1247. SendOnValueChangedAndUpdateLabel();
  1248. }
  1249. }
  1250. else if (m_HideMobileInput && m_Keyboard.canSetSelection)
  1251. {
  1252. var selectionStart = Mathf.Min(caretSelectPositionInternal, caretPositionInternal);
  1253. var selectionLength = Mathf.Abs(caretSelectPositionInternal - caretPositionInternal);
  1254. m_Keyboard.selection = new RangeInt(selectionStart, selectionLength);
  1255. }
  1256. else if (m_Keyboard.canGetSelection && !m_HideMobileInput)
  1257. {
  1258. UpdateCaretFromKeyboard();
  1259. }
  1260. if (m_Keyboard.status != TouchScreenKeyboard.Status.Visible)
  1261. {
  1262. if (m_Keyboard.status == TouchScreenKeyboard.Status.Canceled)
  1263. m_WasCanceled = true;
  1264. OnDeselect(null);
  1265. }
  1266. }
  1267. [Obsolete("This function is no longer used. Please use RectTransformUtility.ScreenPointToLocalPointInRectangle() instead.")]
  1268. public Vector2 ScreenToLocal(Vector2 screen)
  1269. {
  1270. var theCanvas = m_TextComponent.canvas;
  1271. if (theCanvas == null)
  1272. return screen;
  1273. Vector3 pos = Vector3.zero;
  1274. if (theCanvas.renderMode == RenderMode.ScreenSpaceOverlay)
  1275. {
  1276. pos = m_TextComponent.transform.InverseTransformPoint(screen);
  1277. }
  1278. else if (theCanvas.worldCamera != null)
  1279. {
  1280. Ray mouseRay = theCanvas.worldCamera.ScreenPointToRay(screen);
  1281. float dist;
  1282. Plane plane = new Plane(m_TextComponent.transform.forward, m_TextComponent.transform.position);
  1283. plane.Raycast(mouseRay, out dist);
  1284. pos = m_TextComponent.transform.InverseTransformPoint(mouseRay.GetPoint(dist));
  1285. }
  1286. return new Vector2(pos.x, pos.y);
  1287. }
  1288. private int GetUnclampedCharacterLineFromPosition(Vector2 pos, TextGenerator generator)
  1289. {
  1290. if (!multiLine)
  1291. return 0;
  1292. // transform y to local scale
  1293. float y = pos.y * m_TextComponent.pixelsPerUnit;
  1294. float lastBottomY = 0.0f;
  1295. for (int i = 0; i < generator.lineCount; ++i)
  1296. {
  1297. float topY = generator.lines[i].topY;
  1298. float bottomY = topY - generator.lines[i].height;
  1299. // pos is somewhere in the leading above this line
  1300. if (y > topY)
  1301. {
  1302. // determine which line we're closer to
  1303. float leading = topY - lastBottomY;
  1304. if (y > topY - 0.5f * leading)
  1305. return i - 1;
  1306. else
  1307. return i;
  1308. }
  1309. if (y > bottomY)
  1310. return i;
  1311. lastBottomY = bottomY;
  1312. }
  1313. // Position is after last line.
  1314. return generator.lineCount;
  1315. }
  1316. /// <summary>
  1317. /// Given an input position in local space on the Text return the index for the selection cursor at this position.
  1318. /// </summary>
  1319. /// <param name="pos">Mouse position.</param>
  1320. /// <returns>Character index with in value.</returns>
  1321. protected int GetCharacterIndexFromPosition(Vector2 pos)
  1322. {
  1323. TextGenerator gen = m_TextComponent.cachedTextGenerator;
  1324. if (gen.lineCount == 0)
  1325. return 0;
  1326. int line = GetUnclampedCharacterLineFromPosition(pos, gen);
  1327. if (line < 0)
  1328. return 0;
  1329. if (line >= gen.lineCount)
  1330. return gen.characterCountVisible;
  1331. int startCharIndex = gen.lines[line].startCharIdx;
  1332. int endCharIndex = GetLineEndPosition(gen, line);
  1333. for (int i = startCharIndex; i < endCharIndex; i++)
  1334. {
  1335. if (i >= gen.characterCountVisible)
  1336. break;
  1337. UICharInfo charInfo = gen.characters[i];
  1338. Vector2 charPos = charInfo.cursorPos / m_TextComponent.pixelsPerUnit;
  1339. float distToCharStart = pos.x - charPos.x;
  1340. float distToCharEnd = charPos.x + (charInfo.charWidth / m_TextComponent.pixelsPerUnit) - pos.x;
  1341. if (distToCharStart < distToCharEnd)
  1342. return i;
  1343. }
  1344. return endCharIndex;
  1345. }
  1346. private bool MayDrag(PointerEventData eventData)
  1347. {
  1348. return IsActive() &&
  1349. IsInteractable() &&
  1350. eventData.button == PointerEventData.InputButton.Left &&
  1351. m_TextComponent != null &&
  1352. (InPlaceEditing() || m_HideMobileInput);
  1353. }
  1354. /// <summary>
  1355. /// Capture the OnBeginDrag callback from the EventSystem and ensure we should listen to the drag events to follow.
  1356. /// </summary>
  1357. /// <param name="eventData">The data passed by the EventSystem</param>
  1358. public virtual void OnBeginDrag(PointerEventData eventData)
  1359. {
  1360. if (!MayDrag(eventData))
  1361. return;
  1362. m_UpdateDrag = true;
  1363. }
  1364. /// <summary>
  1365. /// If we are able to drag, try and select the character range underneath the bounding rect.
  1366. /// </summary>
  1367. /// <param name="eventData"></param>
  1368. public virtual void OnDrag(PointerEventData eventData)
  1369. {
  1370. if (!MayDrag(eventData))
  1371. return;
  1372. Vector2 position = Vector2.zero;
  1373. if (!MultipleDisplayUtilities.GetRelativeMousePositionForDrag(eventData, ref position))
  1374. return;
  1375. Vector2 localMousePos;
  1376. RectTransformUtility.ScreenPointToLocalPointInRectangle(textComponent.rectTransform, position, eventData.pressEventCamera, out localMousePos);
  1377. caretSelectPositionInternal = GetCharacterIndexFromPosition(localMousePos) + m_DrawStart;
  1378. MarkGeometryAsDirty();
  1379. m_DragPositionOutOfBounds = !RectTransformUtility.RectangleContainsScreenPoint(textComponent.rectTransform, eventData.position, eventData.pressEventCamera);
  1380. if (m_DragPositionOutOfBounds && m_DragCoroutine == null)
  1381. m_DragCoroutine = StartCoroutine(MouseDragOutsideRect(eventData));
  1382. eventData.Use();
  1383. }
  1384. IEnumerator MouseDragOutsideRect(PointerEventData eventData)
  1385. {
  1386. while (m_UpdateDrag && m_DragPositionOutOfBounds)
  1387. {
  1388. Vector2 position = Vector2.zero;
  1389. if (!MultipleDisplayUtilities.GetRelativeMousePositionForDrag(eventData, ref position))
  1390. break;
  1391. Vector2 localMousePos;
  1392. RectTransformUtility.ScreenPointToLocalPointInRectangle(textComponent.rectTransform, position, eventData.pressEventCamera, out localMousePos);
  1393. Rect rect = textComponent.rectTransform.rect;
  1394. if (multiLine)
  1395. {
  1396. if (localMousePos.y > rect.yMax)
  1397. MoveUp(true, true);
  1398. else if (localMousePos.y < rect.yMin)
  1399. MoveDown(true, true);
  1400. }
  1401. else
  1402. {
  1403. if (localMousePos.x < rect.xMin)
  1404. MoveLeft(true, false);
  1405. else if (localMousePos.x > rect.xMax)
  1406. MoveRight(true, false);
  1407. }
  1408. UpdateLabel();
  1409. float delay = multiLine ? kVScrollSpeed : kHScrollSpeed;
  1410. if (m_WaitForSecondsRealtime == null)
  1411. m_WaitForSecondsRealtime = new WaitForSecondsRealtime(delay);
  1412. else
  1413. m_WaitForSecondsRealtime.waitTime = delay;
  1414. yield return m_WaitForSecondsRealtime;
  1415. }
  1416. m_DragCoroutine = null;
  1417. }
  1418. /// <summary>
  1419. /// Capture the OnEndDrag callback from the EventSystem and cancel the listening of drag events.
  1420. /// </summary>
  1421. /// <param name="eventData">The eventData sent by the EventSystem.</param>
  1422. public virtual void OnEndDrag(PointerEventData eventData)
  1423. {
  1424. if (!MayDrag(eventData))
  1425. return;
  1426. m_UpdateDrag = false;
  1427. }
  1428. /// <summary>
  1429. /// The action to perform when the event system sends a pointer down Event.
  1430. /// </summary>
  1431. public override void OnPointerDown(PointerEventData eventData)
  1432. {
  1433. if (!MayDrag(eventData))
  1434. return;
  1435. EventSystem.current.SetSelectedGameObject(gameObject, eventData);
  1436. bool hadFocusBefore = m_AllowInput;
  1437. base.OnPointerDown(eventData);
  1438. if (!InPlaceEditing())
  1439. {
  1440. if (m_Keyboard == null || !m_Keyboard.active)
  1441. {
  1442. OnSelect(eventData);
  1443. return;
  1444. }
  1445. }
  1446. // Only set caret position if we didn't just get focus now.
  1447. // Otherwise it will overwrite the select all on focus.
  1448. if (hadFocusBefore)
  1449. {
  1450. Vector2 localMousePos;
  1451. RectTransformUtility.ScreenPointToLocalPointInRectangle(textComponent.rectTransform, eventData.pointerPressRaycast.screenPosition, eventData.pressEventCamera, out localMousePos);
  1452. caretSelectPositionInternal = caretPositionInternal = GetCharacterIndexFromPosition(localMousePos) + m_DrawStart;
  1453. }
  1454. UpdateLabel();
  1455. eventData.Use();
  1456. }
  1457. protected enum EditState
  1458. {
  1459. Continue,
  1460. Finish
  1461. }
  1462. /// <summary>
  1463. /// Process the Event and perform the appropriate action for that key.
  1464. /// </summary>
  1465. /// <param name="evt">The Event that is currently being processed.</param>
  1466. /// <returns>If we should continue processing events or we have hit an end condition.</returns>
  1467. protected EditState KeyPressed(Event evt)
  1468. {
  1469. var currentEventModifiers = evt.modifiers;
  1470. bool ctrl = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX ? (currentEventModifiers & EventModifiers.Command) != 0 : (currentEventModifiers & EventModifiers.Control) != 0;
  1471. bool shift = (currentEventModifiers & EventModifiers.Shift) != 0;
  1472. bool alt = (currentEventModifiers & EventModifiers.Alt) != 0;
  1473. bool ctrlOnly = ctrl && !alt && !shift;
  1474. bool shiftOnly = shift && !ctrl && !alt;
  1475. switch (evt.keyCode)
  1476. {
  1477. case KeyCode.Backspace:
  1478. {
  1479. Backspace();
  1480. return EditState.Continue;
  1481. }
  1482. case KeyCode.Delete:
  1483. {
  1484. ForwardSpace();
  1485. return EditState.Continue;
  1486. }
  1487. case KeyCode.Home:
  1488. {
  1489. MoveTextStart(shift);
  1490. return EditState.Continue;
  1491. }
  1492. case KeyCode.End:
  1493. {
  1494. MoveTextEnd(shift);
  1495. return EditState.Continue;
  1496. }
  1497. // Select All
  1498. case KeyCode.A:
  1499. {
  1500. if (ctrlOnly)
  1501. {
  1502. SelectAll();
  1503. return EditState.Continue;
  1504. }
  1505. break;
  1506. }
  1507. // Copy
  1508. case KeyCode.C:
  1509. {
  1510. if (ctrlOnly)
  1511. {
  1512. if (inputType != InputType.Password)
  1513. clipboard = GetSelectedString();
  1514. else
  1515. clipboard = "";
  1516. return EditState.Continue;
  1517. }
  1518. break;
  1519. }
  1520. // Paste
  1521. case KeyCode.V:
  1522. {
  1523. if (ctrlOnly)
  1524. {
  1525. Append(clipboard);
  1526. UpdateLabel();
  1527. return EditState.Continue;
  1528. }
  1529. break;
  1530. }
  1531. // Cut
  1532. case KeyCode.X:
  1533. {
  1534. if (ctrlOnly)
  1535. {
  1536. if (inputType != InputType.Password)
  1537. clipboard = GetSelectedString();
  1538. else
  1539. clipboard = "";
  1540. Delete();
  1541. UpdateTouchKeyboardFromEditChanges();
  1542. SendOnValueChangedAndUpdateLabel();
  1543. return EditState.Continue;
  1544. }
  1545. break;
  1546. }
  1547. case KeyCode.Insert:
  1548. {
  1549. // Copy via Insert key
  1550. if (ctrlOnly)
  1551. {
  1552. if (inputType != InputType.Password)
  1553. clipboard = GetSelectedString();
  1554. else
  1555. clipboard = "";
  1556. return EditState.Continue;
  1557. }
  1558. // Paste via insert key.
  1559. else if (shiftOnly)
  1560. {
  1561. Append(clipboard);
  1562. UpdateLabel();
  1563. return EditState.Continue;
  1564. }
  1565. break;
  1566. }
  1567. case KeyCode.LeftArrow:
  1568. {
  1569. MoveLeft(shift, ctrl);
  1570. return EditState.Continue;
  1571. }
  1572. case KeyCode.RightArrow:
  1573. {
  1574. MoveRight(shift, ctrl);
  1575. return EditState.Continue;
  1576. }
  1577. case KeyCode.UpArrow:
  1578. {
  1579. MoveUp(shift);
  1580. return EditState.Continue;
  1581. }
  1582. case KeyCode.DownArrow:
  1583. {
  1584. MoveDown(shift);
  1585. return EditState.Continue;
  1586. }
  1587. // Submit
  1588. case KeyCode.Return:
  1589. case KeyCode.KeypadEnter:
  1590. {
  1591. if (lineType != LineType.MultiLineNewline)
  1592. {
  1593. return EditState.Finish;
  1594. }
  1595. break;
  1596. }
  1597. case KeyCode.Escape:
  1598. {
  1599. m_WasCanceled = true;
  1600. return EditState.Finish;
  1601. }
  1602. }
  1603. char c = evt.character;
  1604. // Don't allow return chars or tabulator key to be entered into single line fields.
  1605. if (!multiLine && (c == '\t' || c == '\r' || c == 10))
  1606. return EditState.Continue;
  1607. // Convert carriage return and end-of-text characters to newline.
  1608. if (c == '\r' || (int)c == 3)
  1609. c = '\n';
  1610. if (IsValidChar(c))
  1611. {
  1612. Append(c);
  1613. }
  1614. if (c == 0)
  1615. {
  1616. if (compositionString.Length > 0)
  1617. {
  1618. UpdateLabel();
  1619. }
  1620. }
  1621. return EditState.Continue;
  1622. }
  1623. private bool IsValidChar(char c)
  1624. {
  1625. // Delete key on mac
  1626. if ((int)c == 127)
  1627. return false;
  1628. // Accept newline and tab
  1629. if (c == '\t' || c == '\n')
  1630. return true;
  1631. return m_TextComponent.font.HasCharacter(c);
  1632. }
  1633. /// <summary>
  1634. /// Handle the specified event.
  1635. /// </summary>
  1636. private Event m_ProcessingEvent = new Event();
  1637. /// <summary>
  1638. /// Helper function to allow separate events to be processed by the InputField.
  1639. /// </summary>
  1640. /// <param name="e">The Event to process</param>
  1641. public void ProcessEvent(Event e)
  1642. {
  1643. KeyPressed(e);
  1644. }
  1645. /// <summary>
  1646. /// What to do when the event system sends a Update selected Event.
  1647. /// </summary>
  1648. /// <param name="eventData">The data on which to process.</param>
  1649. public virtual void OnUpdateSelected(BaseEventData eventData)
  1650. {
  1651. if (!isFocused)
  1652. return;
  1653. bool consumedEvent = false;
  1654. while (Event.PopEvent(m_ProcessingEvent))
  1655. {
  1656. if (m_ProcessingEvent.rawType == EventType.KeyDown)
  1657. {
  1658. consumedEvent = true;
  1659. var shouldContinue = KeyPressed(m_ProcessingEvent);
  1660. if (shouldContinue == EditState.Finish)
  1661. {
  1662. DeactivateInputField();
  1663. break;
  1664. }
  1665. }
  1666. switch (m_ProcessingEvent.type)
  1667. {
  1668. case EventType.ValidateCommand:
  1669. case EventType.ExecuteCommand:
  1670. switch (m_ProcessingEvent.commandName)
  1671. {
  1672. case "SelectAll":
  1673. SelectAll();
  1674. consumedEvent = true;
  1675. break;
  1676. }
  1677. break;
  1678. }
  1679. }
  1680. if (consumedEvent)
  1681. UpdateLabel();
  1682. eventData.Use();
  1683. }
  1684. private string GetSelectedString()
  1685. {
  1686. if (!hasSelection)
  1687. return "";
  1688. int startPos = caretPositionInternal;
  1689. int endPos = caretSelectPositionInternal;
  1690. // Ensure startPos is always less then endPos to make the code simpler
  1691. if (startPos > endPos)
  1692. {
  1693. int temp = startPos;
  1694. startPos = endPos;
  1695. endPos = temp;
  1696. }
  1697. return text.Substring(startPos, endPos - startPos);
  1698. }
  1699. private int FindtNextWordBegin()
  1700. {
  1701. if (caretSelectPositionInternal + 1 >= text.Length)
  1702. return text.Length;
  1703. int spaceLoc = text.IndexOfAny(kSeparators, caretSelectPositionInternal + 1);
  1704. if (spaceLoc == -1)
  1705. spaceLoc = text.Length;
  1706. else
  1707. spaceLoc++;
  1708. return spaceLoc;
  1709. }
  1710. private void MoveRight(bool shift, bool ctrl)
  1711. {
  1712. if (hasSelection && !shift)
  1713. {
  1714. // By convention, if we have a selection and move right without holding shift,
  1715. // we just place the cursor at the end.
  1716. caretPositionInternal = caretSelectPositionInternal = Mathf.Max(caretPositionInternal, caretSelectPositionInternal);
  1717. return;
  1718. }
  1719. int position;
  1720. if (ctrl)
  1721. position = FindtNextWordBegin();
  1722. else
  1723. position = caretSelectPositionInternal + 1;
  1724. if (shift)
  1725. caretSelectPositionInternal = position;
  1726. else
  1727. caretSelectPositionInternal = caretPositionInternal = position;
  1728. }
  1729. private int FindtPrevWordBegin()
  1730. {
  1731. if (caretSelectPositionInternal - 2 < 0)
  1732. return 0;
  1733. int spaceLoc = text.LastIndexOfAny(kSeparators, caretSelectPositionInternal - 2);
  1734. if (spaceLoc == -1)
  1735. spaceLoc = 0;
  1736. else
  1737. spaceLoc++;
  1738. return spaceLoc;
  1739. }
  1740. private void MoveLeft(bool shift, bool ctrl)
  1741. {
  1742. if (hasSelection && !shift)
  1743. {
  1744. // By convention, if we have a selection and move left without holding shift,
  1745. // we just place the cursor at the start.
  1746. caretPositionInternal = caretSelectPositionInternal = Mathf.Min(caretPositionInternal, caretSelectPositionInternal);
  1747. return;
  1748. }
  1749. int position;
  1750. if (ctrl)
  1751. position = FindtPrevWordBegin();
  1752. else
  1753. position = caretSelectPositionInternal - 1;
  1754. if (shift)
  1755. caretSelectPositionInternal = position;
  1756. else
  1757. caretSelectPositionInternal = caretPositionInternal = position;
  1758. }
  1759. private int DetermineCharacterLine(int charPos, TextGenerator generator)
  1760. {
  1761. for (int i = 0; i < generator.lineCount - 1; ++i)
  1762. {
  1763. if (generator.lines[i + 1].startCharIdx > charPos)
  1764. return i;
  1765. }
  1766. return generator.lineCount - 1;
  1767. }
  1768. /// <summary>
  1769. /// Use cachedInputTextGenerator as the y component for the UICharInfo is not required
  1770. /// </summary>
  1771. private int LineUpCharacterPosition(int originalPos, bool goToFirstChar)
  1772. {
  1773. if (originalPos >= cachedInputTextGenerator.characters.Count)
  1774. return 0;
  1775. UICharInfo originChar = cachedInputTextGenerator.characters[originalPos];
  1776. int originLine = DetermineCharacterLine(originalPos, cachedInputTextGenerator);
  1777. // We are on the first line return first character
  1778. if (originLine <= 0)
  1779. return goToFirstChar ? 0 : originalPos;
  1780. int endCharIdx = cachedInputTextGenerator.lines[originLine].startCharIdx - 1;
  1781. for (int i = cachedInputTextGenerator.lines[originLine - 1].startCharIdx; i < endCharIdx; ++i)
  1782. {
  1783. if (cachedInputTextGenerator.characters[i].cursorPos.x >= originChar.cursorPos.x)
  1784. return i;
  1785. }
  1786. return endCharIdx;
  1787. }
  1788. /// <summary>
  1789. /// Use cachedInputTextGenerator as the y component for the UICharInfo is not required
  1790. /// </summary>
  1791. private int LineDownCharacterPosition(int originalPos, bool goToLastChar)
  1792. {
  1793. if (originalPos >= cachedInputTextGenerator.characterCountVisible)
  1794. return text.Length;
  1795. UICharInfo originChar = cachedInputTextGenerator.characters[originalPos];
  1796. int originLine = DetermineCharacterLine(originalPos, cachedInputTextGenerator);
  1797. // We are on the last line return last character
  1798. if (originLine + 1 >= cachedInputTextGenerator.lineCount)
  1799. return goToLastChar ? text.Length : originalPos;
  1800. // Need to determine end line for next line.
  1801. int endCharIdx = GetLineEndPosition(cachedInputTextGenerator, originLine + 1);
  1802. for (int i = cachedInputTextGenerator.lines[originLine + 1].startCharIdx; i < endCharIdx; ++i)
  1803. {
  1804. if (cachedInputTextGenerator.characters[i].cursorPos.x >= originChar.cursorPos.x)
  1805. return i;
  1806. }
  1807. return endCharIdx;
  1808. }
  1809. private void MoveDown(bool shift)
  1810. {
  1811. MoveDown(shift, true);
  1812. }
  1813. private void MoveDown(bool shift, bool goToLastChar)
  1814. {
  1815. if (hasSelection && !shift)
  1816. {
  1817. // If we have a selection and press down without shift,
  1818. // set caret position to end of selection before we move it down.
  1819. caretPositionInternal = caretSelectPositionInternal = Mathf.Max(caretPositionInternal, caretSelectPositionInternal);
  1820. }
  1821. int position = multiLine ? LineDownCharacterPosition(caretSelectPositionInternal, goToLastChar) : text.Length;
  1822. if (shift)
  1823. caretSelectPositionInternal = position;
  1824. else
  1825. caretPositionInternal = caretSelectPositionInternal = position;
  1826. }
  1827. private void MoveUp(bool shift)
  1828. {
  1829. MoveUp(shift, true);
  1830. }
  1831. private void MoveUp(bool shift, bool goToFirstChar)
  1832. {
  1833. if (hasSelection && !shift)
  1834. {
  1835. // If we have a selection and press up without shift,
  1836. // set caret position to start of selection before we move it up.
  1837. caretPositionInternal = caretSelectPositionInternal = Mathf.Min(caretPositionInternal, caretSelectPositionInternal);
  1838. }
  1839. int position = multiLine ? LineUpCharacterPosition(caretSelectPositionInternal, goToFirstChar) : 0;
  1840. if (shift)
  1841. caretSelectPositionInternal = position;
  1842. else
  1843. caretSelectPositionInternal = caretPositionInternal = position;
  1844. }
  1845. private void Delete()
  1846. {
  1847. if (m_ReadOnly)
  1848. return;
  1849. if (caretPositionInternal == caretSelectPositionInternal)
  1850. return;
  1851. if (caretPositionInternal < caretSelectPositionInternal)
  1852. {
  1853. m_Text = text.Substring(0, caretPositionInternal) + text.Substring(caretSelectPositionInternal, text.Length - caretSelectPositionInternal);
  1854. caretSelectPositionInternal = caretPositionInternal;
  1855. }
  1856. else
  1857. {
  1858. m_Text = text.Substring(0, caretSelectPositionInternal) + text.Substring(caretPositionInternal, text.Length - caretPositionInternal);
  1859. caretPositionInternal = caretSelectPositionInternal;
  1860. }
  1861. }
  1862. private void ForwardSpace()
  1863. {
  1864. if (m_ReadOnly)
  1865. return;
  1866. if (hasSelection)
  1867. {
  1868. Delete();
  1869. UpdateTouchKeyboardFromEditChanges();
  1870. SendOnValueChangedAndUpdateLabel();
  1871. }
  1872. else
  1873. {
  1874. if (caretPositionInternal < text.Length)
  1875. {
  1876. m_Text = text.Remove(caretPositionInternal, 1);
  1877. UpdateTouchKeyboardFromEditChanges();
  1878. SendOnValueChangedAndUpdateLabel();
  1879. }
  1880. }
  1881. }
  1882. private void Backspace()
  1883. {
  1884. if (m_ReadOnly)
  1885. return;
  1886. if (hasSelection)
  1887. {
  1888. Delete();
  1889. UpdateTouchKeyboardFromEditChanges();
  1890. SendOnValueChangedAndUpdateLabel();
  1891. }
  1892. else
  1893. {
  1894. if (caretPositionInternal > 0)
  1895. {
  1896. m_Text = text.Remove(caretPositionInternal - 1, 1);
  1897. caretSelectPositionInternal = caretPositionInternal = caretPositionInternal - 1;
  1898. UpdateTouchKeyboardFromEditChanges();
  1899. SendOnValueChangedAndUpdateLabel();
  1900. }
  1901. }
  1902. }
  1903. // Insert the character and update the label.
  1904. private void Insert(char c)
  1905. {
  1906. if (m_ReadOnly)
  1907. return;
  1908. string replaceString = c.ToString();
  1909. Delete();
  1910. // Can't go past the character limit
  1911. if (characterLimit > 0 && text.Length >= characterLimit)
  1912. return;
  1913. m_Text = text.Insert(m_CaretPosition, replaceString);
  1914. caretSelectPositionInternal = caretPositionInternal += replaceString.Length;
  1915. UpdateTouchKeyboardFromEditChanges();
  1916. SendOnValueChanged();
  1917. }
  1918. private void UpdateTouchKeyboardFromEditChanges()
  1919. {
  1920. // Update the TouchKeyboard's text from edit changes
  1921. // if in-place editing is allowed
  1922. if (m_Keyboard != null && InPlaceEditing())
  1923. {
  1924. m_Keyboard.text = m_Text;
  1925. }
  1926. }
  1927. private void SendOnValueChangedAndUpdateLabel()
  1928. {
  1929. SendOnValueChanged();
  1930. UpdateLabel();
  1931. }
  1932. private void SendOnValueChanged()
  1933. {
  1934. UISystemProfilerApi.AddMarker("InputField.value", this);
  1935. if (onValueChanged != null)
  1936. onValueChanged.Invoke(text);
  1937. }
  1938. /// <summary>
  1939. /// Convenience function to make functionality to send the ::ref::SubmitEvent easier.
  1940. /// </summary>
  1941. protected void SendOnSubmit()
  1942. {
  1943. UISystemProfilerApi.AddMarker("InputField.onSubmit", this);
  1944. if (onEndEdit != null)
  1945. onEndEdit.Invoke(m_Text);
  1946. }
  1947. /// <summary>
  1948. /// Append the specified text to the end of the current text string. Appends character by character testing validation criteria.
  1949. /// </summary>
  1950. /// <param name="input">The String to append.</param>
  1951. protected virtual void Append(string input)
  1952. {
  1953. if (m_ReadOnly)
  1954. return;
  1955. if (!InPlaceEditing())
  1956. return;
  1957. for (int i = 0, imax = input.Length; i < imax; ++i)
  1958. {
  1959. char c = input[i];
  1960. if (c >= ' ' || c == '\t' || c == '\r' || c == 10 || c == '\n')
  1961. {
  1962. Append(c);
  1963. }
  1964. }
  1965. }
  1966. // cf. TextGenerator.cpp
  1967. private const int k_MaxTextLength = UInt16.MaxValue / 4 - 1;
  1968. /// <summary>
  1969. /// Append a character to the input field, taking into account the validation of each character.
  1970. /// </summary>
  1971. /// <param name="input">Character to append.</param>
  1972. protected virtual void Append(char input)
  1973. {
  1974. // We do not currently support surrogate pairs
  1975. if (char.IsSurrogate(input))
  1976. return;
  1977. if (m_ReadOnly || text.Length >= k_MaxTextLength)
  1978. return;
  1979. if (!InPlaceEditing())
  1980. return;
  1981. // If we have an input validator, validate the input first
  1982. int insertionPoint = Math.Min(selectionFocusPosition, selectionAnchorPosition);
  1983. //Get the text based on selection for validation instead of whole text(case 1253193).
  1984. var validateText = text;
  1985. if (selectionFocusPosition != selectionAnchorPosition)
  1986. {
  1987. if (caretPositionInternal < caretSelectPositionInternal)
  1988. {
  1989. validateText = text.Substring(0, caretPositionInternal) + text.Substring(caretSelectPositionInternal, text.Length - caretSelectPositionInternal);
  1990. }
  1991. else
  1992. {
  1993. validateText = text.Substring(0, caretSelectPositionInternal) + text.Substring(caretPositionInternal, text.Length - caretPositionInternal);
  1994. }
  1995. }
  1996. if (onValidateInput != null)
  1997. input = onValidateInput(validateText, insertionPoint, input);
  1998. else if (characterValidation != CharacterValidation.None)
  1999. input = Validate(validateText, insertionPoint, input);
  2000. // If the input is invalid, skip it
  2001. if (input == 0)
  2002. return;
  2003. // Append the character and update the label
  2004. Insert(input);
  2005. }
  2006. /// <summary>
  2007. /// Update the Text associated with this input field.
  2008. /// </summary>
  2009. protected void UpdateLabel()
  2010. {
  2011. if (m_TextComponent != null && m_TextComponent.font != null && !m_PreventFontCallback)
  2012. {
  2013. // TextGenerator.Populate invokes a callback that's called for anything
  2014. // that needs to be updated when the data for that font has changed.
  2015. // This makes all Text components that use that font update their vertices.
  2016. // In turn, this makes the InputField that's associated with that Text component
  2017. // update its label by calling this UpdateLabel method.
  2018. // This is a recursive call we want to prevent, since it makes the InputField
  2019. // update based on font data that didn't yet finish executing, or alternatively
  2020. // hang on infinite recursion, depending on whether the cached value is cached
  2021. // before or after the calculation.
  2022. //
  2023. // This callback also occurs when assigning text to our Text component, i.e.,
  2024. // m_TextComponent.text = processed;
  2025. m_PreventFontCallback = true;
  2026. string fullText;
  2027. if (EventSystem.current != null && gameObject == EventSystem.current.currentSelectedGameObject && compositionString.Length > 0)
  2028. fullText = text.Substring(0, m_CaretPosition) + compositionString + text.Substring(m_CaretPosition);
  2029. else
  2030. fullText = text;
  2031. string processed;
  2032. if (inputType == InputType.Password)
  2033. processed = new string(asteriskChar, fullText.Length);
  2034. else
  2035. processed = fullText;
  2036. bool isEmpty = string.IsNullOrEmpty(fullText);
  2037. if (m_Placeholder != null)
  2038. m_Placeholder.enabled = isEmpty;
  2039. // If not currently editing the text, set the visible range to the whole text.
  2040. // The UpdateLabel method will then truncate it to the part that fits inside the Text area.
  2041. // We can't do this when text is being edited since it would discard the current scroll,
  2042. // which is defined by means of the m_DrawStart and m_DrawEnd indices.
  2043. if (!m_AllowInput)
  2044. {
  2045. m_DrawStart = 0;
  2046. m_DrawEnd = m_Text.Length;
  2047. }
  2048. if (!isEmpty)
  2049. {
  2050. // Determine what will actually fit into the given line
  2051. Vector2 extents = m_TextComponent.rectTransform.rect.size;
  2052. var settings = m_TextComponent.GetGenerationSettings(extents);
  2053. settings.generateOutOfBounds = true;
  2054. cachedInputTextGenerator.PopulateWithErrors(processed, settings, gameObject);
  2055. SetDrawRangeToContainCaretPosition(caretSelectPositionInternal);
  2056. processed = processed.Substring(m_DrawStart, Mathf.Min(m_DrawEnd, processed.Length) - m_DrawStart);
  2057. SetCaretVisible();
  2058. }
  2059. m_TextComponent.text = processed;
  2060. MarkGeometryAsDirty();
  2061. m_PreventFontCallback = false;
  2062. }
  2063. }
  2064. private bool IsSelectionVisible()
  2065. {
  2066. if (m_DrawStart > caretPositionInternal || m_DrawStart > caretSelectPositionInternal)
  2067. return false;
  2068. if (m_DrawEnd < caretPositionInternal || m_DrawEnd < caretSelectPositionInternal)
  2069. return false;
  2070. return true;
  2071. }
  2072. private static int GetLineStartPosition(TextGenerator gen, int line)
  2073. {
  2074. line = Mathf.Clamp(line, 0, gen.lines.Count - 1);
  2075. return gen.lines[line].startCharIdx;
  2076. }
  2077. private static int GetLineEndPosition(TextGenerator gen, int line)
  2078. {
  2079. line = Mathf.Max(line, 0);
  2080. if (line + 1 < gen.lines.Count)
  2081. return gen.lines[line + 1].startCharIdx - 1;
  2082. return gen.characterCountVisible;
  2083. }
  2084. private void SetDrawRangeToContainCaretPosition(int caretPos)
  2085. {
  2086. // We don't have any generated lines generation is not valid.
  2087. if (cachedInputTextGenerator.lineCount <= 0)
  2088. return;
  2089. // the extents gets modified by the pixel density, so we need to use the generated extents since that will be in the same 'space' as
  2090. // the values returned by the TextGenerator.lines[x].height for instance.
  2091. Vector2 extents = cachedInputTextGenerator.rectExtents.size;
  2092. if (multiLine)
  2093. {
  2094. var lines = cachedInputTextGenerator.lines;
  2095. int caretLine = DetermineCharacterLine(caretPos, cachedInputTextGenerator);
  2096. if (caretPos > m_DrawEnd)
  2097. {
  2098. // Caret comes after drawEnd, so we need to move drawEnd to the end of the line with the caret
  2099. m_DrawEnd = GetLineEndPosition(cachedInputTextGenerator, caretLine);
  2100. float bottomY = lines[caretLine].topY - lines[caretLine].height;
  2101. if (caretLine == lines.Count - 1)
  2102. {
  2103. // Remove interline spacing on last line.
  2104. bottomY += lines[caretLine].leading;
  2105. }
  2106. int startLine = caretLine;
  2107. while (startLine > 0)
  2108. {
  2109. float topY = lines[startLine - 1].topY;
  2110. if (topY - bottomY > extents.y)
  2111. break;
  2112. startLine--;
  2113. }
  2114. m_DrawStart = GetLineStartPosition(cachedInputTextGenerator, startLine);
  2115. }
  2116. else
  2117. {
  2118. if (caretPos < m_DrawStart)
  2119. {
  2120. // Caret comes before drawStart, so we need to move drawStart to an earlier line start that comes before caret.
  2121. m_DrawStart = GetLineStartPosition(cachedInputTextGenerator, caretLine);
  2122. }
  2123. int startLine = DetermineCharacterLine(m_DrawStart, cachedInputTextGenerator);
  2124. int endLine = startLine;
  2125. float topY = lines[startLine].topY;
  2126. float bottomY = lines[endLine].topY - lines[endLine].height;
  2127. if (endLine == lines.Count - 1)
  2128. {
  2129. // Remove interline spacing on last line.
  2130. bottomY += lines[endLine].leading;
  2131. }
  2132. while (endLine < lines.Count - 1)
  2133. {
  2134. bottomY = lines[endLine + 1].topY - lines[endLine + 1].height;
  2135. if (endLine + 1 == lines.Count - 1)
  2136. {
  2137. // Remove interline spacing on last line.
  2138. bottomY += lines[endLine + 1].leading;
  2139. }
  2140. if (topY - bottomY > extents.y)
  2141. break;
  2142. ++endLine;
  2143. }
  2144. m_DrawEnd = GetLineEndPosition(cachedInputTextGenerator, endLine);
  2145. while (startLine > 0)
  2146. {
  2147. topY = lines[startLine - 1].topY;
  2148. if (topY - bottomY > extents.y)
  2149. break;
  2150. startLine--;
  2151. }
  2152. m_DrawStart = GetLineStartPosition(cachedInputTextGenerator, startLine);
  2153. }
  2154. }
  2155. else
  2156. {
  2157. var characters = cachedInputTextGenerator.characters;
  2158. if (m_DrawEnd > cachedInputTextGenerator.characterCountVisible)
  2159. m_DrawEnd = cachedInputTextGenerator.characterCountVisible;
  2160. float width = 0.0f;
  2161. if (caretPos > m_DrawEnd || (caretPos == m_DrawEnd && m_DrawStart > 0))
  2162. {
  2163. // fit characters from the caretPos leftward
  2164. m_DrawEnd = caretPos;
  2165. for (m_DrawStart = m_DrawEnd - 1; m_DrawStart >= 0; --m_DrawStart)
  2166. {
  2167. if (width + characters[m_DrawStart].charWidth > extents.x)
  2168. break;
  2169. width += characters[m_DrawStart].charWidth;
  2170. }
  2171. ++m_DrawStart; // move right one to the last character we could fit on the left
  2172. }
  2173. else
  2174. {
  2175. if (caretPos < m_DrawStart)
  2176. m_DrawStart = caretPos;
  2177. m_DrawEnd = m_DrawStart;
  2178. }
  2179. // fit characters rightward
  2180. for (; m_DrawEnd < cachedInputTextGenerator.characterCountVisible; ++m_DrawEnd)
  2181. {
  2182. width += characters[m_DrawEnd].charWidth;
  2183. if (width > extents.x)
  2184. break;
  2185. }
  2186. }
  2187. }
  2188. /// <summary>
  2189. /// Force the label to update immediatly. This will recalculate the positioning of the caret and the visible text.
  2190. /// </summary>
  2191. public void ForceLabelUpdate()
  2192. {
  2193. UpdateLabel();
  2194. }
  2195. private void MarkGeometryAsDirty()
  2196. {
  2197. #if UNITY_EDITOR
  2198. if (!Application.isPlaying || UnityEditor.PrefabUtility.IsPartOfPrefabAsset(gameObject))
  2199. return;
  2200. #endif
  2201. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
  2202. }
  2203. /// <summary>
  2204. /// Rebuild the input fields geometry. (caret and highlight).
  2205. /// </summary>
  2206. /// <param name="update">Which update loop we are in.</param>
  2207. public virtual void Rebuild(CanvasUpdate update)
  2208. {
  2209. switch (update)
  2210. {
  2211. case CanvasUpdate.LatePreRender:
  2212. UpdateGeometry();
  2213. break;
  2214. }
  2215. }
  2216. /// <summary>
  2217. /// See ICanvasElement.LayoutComplete. Does nothing by default.
  2218. /// </summary>
  2219. public virtual void LayoutComplete()
  2220. {}
  2221. /// <summary>
  2222. /// See ICanvasElement.GraphicUpdateComplete. Does nothing by default.
  2223. /// </summary>
  2224. public virtual void GraphicUpdateComplete()
  2225. {}
  2226. private void UpdateGeometry()
  2227. {
  2228. #if UNITY_EDITOR
  2229. if (!Application.isPlaying)
  2230. return;
  2231. #endif
  2232. // No need to draw a cursor on mobile as its handled by the devices keyboard.
  2233. if (!InPlaceEditing() && !shouldHideMobileInput)
  2234. return;
  2235. if (m_CachedInputRenderer == null && m_TextComponent != null)
  2236. {
  2237. GameObject go = new GameObject(transform.name + " Input Caret", typeof(RectTransform), typeof(CanvasRenderer));
  2238. go.hideFlags = HideFlags.DontSave;
  2239. go.transform.SetParent(m_TextComponent.transform.parent);
  2240. go.transform.SetAsFirstSibling();
  2241. go.layer = gameObject.layer;
  2242. caretRectTrans = go.GetComponent<RectTransform>();
  2243. m_CachedInputRenderer = go.GetComponent<CanvasRenderer>();
  2244. m_CachedInputRenderer.SetMaterial(m_TextComponent.GetModifiedMaterial(Graphic.defaultGraphicMaterial), Texture2D.whiteTexture);
  2245. // Needed as if any layout is present we want the caret to always be the same as the text area.
  2246. go.AddComponent<LayoutElement>().ignoreLayout = true;
  2247. AssignPositioningIfNeeded();
  2248. }
  2249. if (m_CachedInputRenderer == null)
  2250. return;
  2251. OnFillVBO(mesh);
  2252. m_CachedInputRenderer.SetMesh(mesh);
  2253. }
  2254. private void AssignPositioningIfNeeded()
  2255. {
  2256. if (m_TextComponent != null && caretRectTrans != null &&
  2257. (caretRectTrans.localPosition != m_TextComponent.rectTransform.localPosition ||
  2258. caretRectTrans.localRotation != m_TextComponent.rectTransform.localRotation ||
  2259. caretRectTrans.localScale != m_TextComponent.rectTransform.localScale ||
  2260. caretRectTrans.anchorMin != m_TextComponent.rectTransform.anchorMin ||
  2261. caretRectTrans.anchorMax != m_TextComponent.rectTransform.anchorMax ||
  2262. caretRectTrans.anchoredPosition != m_TextComponent.rectTransform.anchoredPosition ||
  2263. caretRectTrans.sizeDelta != m_TextComponent.rectTransform.sizeDelta ||
  2264. caretRectTrans.pivot != m_TextComponent.rectTransform.pivot))
  2265. {
  2266. caretRectTrans.localPosition = m_TextComponent.rectTransform.localPosition;
  2267. caretRectTrans.localRotation = m_TextComponent.rectTransform.localRotation;
  2268. caretRectTrans.localScale = m_TextComponent.rectTransform.localScale;
  2269. caretRectTrans.anchorMin = m_TextComponent.rectTransform.anchorMin;
  2270. caretRectTrans.anchorMax = m_TextComponent.rectTransform.anchorMax;
  2271. caretRectTrans.anchoredPosition = m_TextComponent.rectTransform.anchoredPosition;
  2272. caretRectTrans.sizeDelta = m_TextComponent.rectTransform.sizeDelta;
  2273. caretRectTrans.pivot = m_TextComponent.rectTransform.pivot;
  2274. }
  2275. }
  2276. private void OnFillVBO(Mesh vbo)
  2277. {
  2278. using (var helper = new VertexHelper())
  2279. {
  2280. if (!isFocused)
  2281. {
  2282. helper.FillMesh(vbo);
  2283. return;
  2284. }
  2285. Vector2 roundingOffset = m_TextComponent.PixelAdjustPoint(Vector2.zero);
  2286. if (!hasSelection)
  2287. GenerateCaret(helper, roundingOffset);
  2288. else
  2289. GenerateHighlight(helper, roundingOffset);
  2290. helper.FillMesh(vbo);
  2291. }
  2292. }
  2293. private void GenerateCaret(VertexHelper vbo, Vector2 roundingOffset)
  2294. {
  2295. if (!m_CaretVisible)
  2296. return;
  2297. if (m_CursorVerts == null)
  2298. {
  2299. CreateCursorVerts();
  2300. }
  2301. float width = m_CaretWidth;
  2302. int adjustedPos = Mathf.Max(0, caretPositionInternal - m_DrawStart);
  2303. TextGenerator gen = m_TextComponent.cachedTextGenerator;
  2304. if (gen == null)
  2305. return;
  2306. if (gen.lineCount == 0)
  2307. return;
  2308. Vector2 startPosition = Vector2.zero;
  2309. // Calculate startPosition
  2310. if (adjustedPos < gen.characters.Count)
  2311. {
  2312. UICharInfo cursorChar = gen.characters[adjustedPos];
  2313. startPosition.x = cursorChar.cursorPos.x;
  2314. }
  2315. startPosition.x /= m_TextComponent.pixelsPerUnit;
  2316. // TODO: Only clamp when Text uses horizontal word wrap.
  2317. if (startPosition.x > m_TextComponent.rectTransform.rect.xMax)
  2318. startPosition.x = m_TextComponent.rectTransform.rect.xMax;
  2319. int characterLine = DetermineCharacterLine(adjustedPos, gen);
  2320. startPosition.y = gen.lines[characterLine].topY / m_TextComponent.pixelsPerUnit;
  2321. float height = gen.lines[characterLine].height / m_TextComponent.pixelsPerUnit;
  2322. for (int i = 0; i < m_CursorVerts.Length; i++)
  2323. m_CursorVerts[i].color = caretColor;
  2324. m_CursorVerts[0].position = new Vector3(startPosition.x, startPosition.y - height, 0.0f);
  2325. m_CursorVerts[1].position = new Vector3(startPosition.x + width, startPosition.y - height, 0.0f);
  2326. m_CursorVerts[2].position = new Vector3(startPosition.x + width, startPosition.y, 0.0f);
  2327. m_CursorVerts[3].position = new Vector3(startPosition.x, startPosition.y, 0.0f);
  2328. if (roundingOffset != Vector2.zero)
  2329. {
  2330. for (int i = 0; i < m_CursorVerts.Length; i++)
  2331. {
  2332. UIVertex uiv = m_CursorVerts[i];
  2333. uiv.position.x += roundingOffset.x;
  2334. uiv.position.y += roundingOffset.y;
  2335. }
  2336. }
  2337. vbo.AddUIVertexQuad(m_CursorVerts);
  2338. int screenHeight = Screen.height;
  2339. // Multiple display support only when not the main display. For display 0 the reported
  2340. // resolution is always the desktops resolution since its part of the display API,
  2341. // so we use the standard none multiple display method. (case 741751)
  2342. int displayIndex = m_TextComponent.canvas.targetDisplay;
  2343. if (displayIndex > 0 && displayIndex < Display.displays.Length)
  2344. screenHeight = Display.displays[displayIndex].renderingHeight;
  2345. // Calculate position of IME Window in screen space.
  2346. Camera cameraRef;
  2347. if (m_TextComponent.canvas.renderMode == RenderMode.ScreenSpaceOverlay)
  2348. cameraRef = null;
  2349. else
  2350. cameraRef = m_TextComponent.canvas.worldCamera;
  2351. Vector3 cursorPosition = m_CachedInputRenderer.gameObject.transform.TransformPoint(m_CursorVerts[0].position);
  2352. Vector2 screenPosition = RectTransformUtility.WorldToScreenPoint(cameraRef, cursorPosition);
  2353. screenPosition.y = screenHeight - screenPosition.y;
  2354. if (input != null)
  2355. input.compositionCursorPos = screenPosition;
  2356. }
  2357. private void CreateCursorVerts()
  2358. {
  2359. m_CursorVerts = new UIVertex[4];
  2360. for (int i = 0; i < m_CursorVerts.Length; i++)
  2361. {
  2362. m_CursorVerts[i] = UIVertex.simpleVert;
  2363. m_CursorVerts[i].uv0 = Vector2.zero;
  2364. }
  2365. }
  2366. private void GenerateHighlight(VertexHelper vbo, Vector2 roundingOffset)
  2367. {
  2368. int startChar = Mathf.Max(0, caretPositionInternal - m_DrawStart);
  2369. int endChar = Mathf.Max(0, caretSelectPositionInternal - m_DrawStart);
  2370. // Ensure pos is always less then selPos to make the code simpler
  2371. if (startChar > endChar)
  2372. {
  2373. int temp = startChar;
  2374. startChar = endChar;
  2375. endChar = temp;
  2376. }
  2377. endChar -= 1;
  2378. TextGenerator gen = m_TextComponent.cachedTextGenerator;
  2379. if (gen.lineCount <= 0)
  2380. return;
  2381. int currentLineIndex = DetermineCharacterLine(startChar, gen);
  2382. int lastCharInLineIndex = GetLineEndPosition(gen, currentLineIndex);
  2383. UIVertex vert = UIVertex.simpleVert;
  2384. vert.uv0 = Vector2.zero;
  2385. vert.color = selectionColor;
  2386. int currentChar = startChar;
  2387. while (currentChar <= endChar && currentChar < gen.characterCount)
  2388. {
  2389. if (currentChar == lastCharInLineIndex || currentChar == endChar)
  2390. {
  2391. UICharInfo startCharInfo = gen.characters[startChar];
  2392. UICharInfo endCharInfo = gen.characters[currentChar];
  2393. Vector2 startPosition = new Vector2(startCharInfo.cursorPos.x / m_TextComponent.pixelsPerUnit, gen.lines[currentLineIndex].topY / m_TextComponent.pixelsPerUnit);
  2394. Vector2 endPosition = new Vector2((endCharInfo.cursorPos.x + endCharInfo.charWidth) / m_TextComponent.pixelsPerUnit, startPosition.y - gen.lines[currentLineIndex].height / m_TextComponent.pixelsPerUnit);
  2395. // Checking xMin as well due to text generator not setting position if char is not rendered.
  2396. if (endPosition.x > m_TextComponent.rectTransform.rect.xMax || endPosition.x < m_TextComponent.rectTransform.rect.xMin)
  2397. endPosition.x = m_TextComponent.rectTransform.rect.xMax;
  2398. var startIndex = vbo.currentVertCount;
  2399. vert.position = new Vector3(startPosition.x, endPosition.y, 0.0f) + (Vector3)roundingOffset;
  2400. vbo.AddVert(vert);
  2401. vert.position = new Vector3(endPosition.x, endPosition.y, 0.0f) + (Vector3)roundingOffset;
  2402. vbo.AddVert(vert);
  2403. vert.position = new Vector3(endPosition.x, startPosition.y, 0.0f) + (Vector3)roundingOffset;
  2404. vbo.AddVert(vert);
  2405. vert.position = new Vector3(startPosition.x, startPosition.y, 0.0f) + (Vector3)roundingOffset;
  2406. vbo.AddVert(vert);
  2407. vbo.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
  2408. vbo.AddTriangle(startIndex + 2, startIndex + 3, startIndex + 0);
  2409. startChar = currentChar + 1;
  2410. currentLineIndex++;
  2411. lastCharInLineIndex = GetLineEndPosition(gen, currentLineIndex);
  2412. }
  2413. currentChar++;
  2414. }
  2415. }
  2416. /// <summary>
  2417. /// Predefined validation functionality for different characterValidation types.
  2418. /// </summary>
  2419. /// <param name="text">The whole text string to validate.</param>
  2420. /// <param name="pos">The position at which the current character is being inserted.</param>
  2421. /// <param name="ch">The character that is being inserted</param>
  2422. /// <returns>The character that should be inserted.</returns>
  2423. protected char Validate(string text, int pos, char ch)
  2424. {
  2425. // Validation is disabled
  2426. if (characterValidation == CharacterValidation.None || !enabled)
  2427. return ch;
  2428. if (characterValidation == CharacterValidation.Integer || characterValidation == CharacterValidation.Decimal)
  2429. {
  2430. // Integer and decimal
  2431. bool cursorBeforeDash = (pos == 0 && text.Length > 0 && text[0] == '-');
  2432. bool dashInSelection = text.Length > 0 && text[0] == '-' && ((caretPositionInternal == 0 && caretSelectPositionInternal > 0) || (caretSelectPositionInternal == 0 && caretPositionInternal > 0));
  2433. bool selectionAtStart = caretPositionInternal == 0 || caretSelectPositionInternal == 0;
  2434. if (!cursorBeforeDash || dashInSelection)
  2435. {
  2436. if (ch >= '0' && ch <= '9') return ch;
  2437. if (ch == '-' && (pos == 0 || selectionAtStart)) return ch;
  2438. if ((ch == '.' || ch == ',') && characterValidation == CharacterValidation.Decimal && text.IndexOfAny(new[] { '.', ',' }) == -1) return ch;
  2439. }
  2440. }
  2441. else if (characterValidation == CharacterValidation.Alphanumeric)
  2442. {
  2443. // All alphanumeric characters
  2444. if (ch >= 'A' && ch <= 'Z') return ch;
  2445. if (ch >= 'a' && ch <= 'z') return ch;
  2446. if (ch >= '0' && ch <= '9') return ch;
  2447. }
  2448. else if (characterValidation == CharacterValidation.Name)
  2449. {
  2450. // FIXME: some actions still lead to invalid input:
  2451. // - Hitting delete in front of an uppercase letter
  2452. // - Selecting an uppercase letter and deleting it
  2453. // - Typing some text, hitting Home and typing more text (we then have an uppercase letter in the middle of a word)
  2454. // - Typing some text, hitting Home and typing a space (we then have a leading space)
  2455. // - Erasing a space between two words (we then have an uppercase letter in the middle of a word)
  2456. // - We accept a trailing space
  2457. // - We accept the insertion of a space between two lowercase letters.
  2458. // - Typing text in front of an existing uppercase letter
  2459. // - ... and certainly more
  2460. //
  2461. // The rule we try to implement are too complex for this kind of verification.
  2462. if (char.IsLetter(ch))
  2463. {
  2464. // Character following a space should be in uppercase.
  2465. if (char.IsLower(ch) && ((pos == 0) || (text[pos - 1] == ' ')))
  2466. {
  2467. return char.ToUpper(ch);
  2468. }
  2469. // Character not following a space or an apostrophe should be in lowercase.
  2470. if (char.IsUpper(ch) && (pos > 0) && (text[pos - 1] != ' ') && (text[pos - 1] != '\''))
  2471. {
  2472. return char.ToLower(ch);
  2473. }
  2474. return ch;
  2475. }
  2476. if (ch == '\'')
  2477. {
  2478. // Don't allow more than one apostrophe
  2479. if (!text.Contains("'"))
  2480. // Don't allow consecutive spaces and apostrophes.
  2481. if (!(((pos > 0) && ((text[pos - 1] == ' ') || (text[pos - 1] == '\''))) ||
  2482. ((pos < text.Length) && ((text[pos] == ' ') || (text[pos] == '\'')))))
  2483. return ch;
  2484. }
  2485. if (ch == ' ')
  2486. {
  2487. if (pos != 0) // Don't allow leading spaces
  2488. {
  2489. // Don't allow consecutive spaces and apostrophes.
  2490. if (!(((pos > 0) && ((text[pos - 1] == ' ') || (text[pos - 1] == '\''))) ||
  2491. ((pos < text.Length) && ((text[pos] == ' ') || (text[pos] == '\'')))))
  2492. return ch;
  2493. }
  2494. }
  2495. }
  2496. else if (characterValidation == CharacterValidation.EmailAddress)
  2497. {
  2498. // From StackOverflow about allowed characters in email addresses:
  2499. // Uppercase and lowercase English letters (a-z, A-Z)
  2500. // Digits 0 to 9
  2501. // Characters ! # $ % & ' * + - / = ? ^ _ ` { | } ~
  2502. // Character . (dot, period, full stop) provided that it is not the first or last character,
  2503. // and provided also that it does not appear two or more times consecutively.
  2504. if (ch >= 'A' && ch <= 'Z') return ch;
  2505. if (ch >= 'a' && ch <= 'z') return ch;
  2506. if (ch >= '0' && ch <= '9') return ch;
  2507. if (ch == '@' && text.IndexOf('@') == -1) return ch;
  2508. if (kEmailSpecialCharacters.IndexOf(ch) != -1) return ch;
  2509. if (ch == '.')
  2510. {
  2511. char lastChar = (text.Length > 0) ? text[Mathf.Clamp(pos, 0, text.Length - 1)] : ' ';
  2512. char nextChar = (text.Length > 0) ? text[Mathf.Clamp(pos + 1, 0, text.Length - 1)] : '\n';
  2513. if (lastChar != '.' && nextChar != '.')
  2514. return ch;
  2515. }
  2516. }
  2517. return (char)0;
  2518. }
  2519. /// <summary>
  2520. /// Function to activate the InputField to begin processing Events.
  2521. /// </summary>
  2522. /// <remarks>
  2523. /// Will only activate if deactivated.
  2524. /// </remarks>
  2525. /// <example>
  2526. /// <code>
  2527. /// using UnityEngine;
  2528. /// using System.Collections;
  2529. /// using UnityEngine.UI;
  2530. ///
  2531. /// public class Example : MonoBehaviour
  2532. /// {
  2533. /// public InputField mainInputField;
  2534. ///
  2535. /// // Activate the main input field when the scene starts.
  2536. /// void Start()
  2537. /// {
  2538. /// mainInputField.ActivateInputField();
  2539. /// }
  2540. /// }
  2541. /// </code>
  2542. /// </example>
  2543. public void ActivateInputField()
  2544. {
  2545. if (m_TextComponent == null || m_TextComponent.font == null || !IsActive() || !IsInteractable())
  2546. return;
  2547. if (isFocused)
  2548. {
  2549. if (m_Keyboard != null && !m_Keyboard.active)
  2550. {
  2551. m_Keyboard.active = true;
  2552. m_Keyboard.text = m_Text;
  2553. }
  2554. }
  2555. m_ShouldActivateNextUpdate = true;
  2556. }
  2557. private void ActivateInputFieldInternal()
  2558. {
  2559. if (EventSystem.current == null)
  2560. return;
  2561. if (EventSystem.current.currentSelectedGameObject != gameObject)
  2562. EventSystem.current.SetSelectedGameObject(gameObject);
  2563. // Cache the value of isInPlaceEditingAllowed, because on UWP this involves calling into native code
  2564. // Usually, the value only needs to be updated once when the TouchKeyboard is opened; however, on Chrome OS,
  2565. // we check repeatedly to see if the in-place editing state has changed, so we can take action.
  2566. m_TouchKeyboardAllowsInPlaceEditing = TouchScreenKeyboard.isInPlaceEditingAllowed;
  2567. if (TouchScreenKeyboardShouldBeUsed())
  2568. {
  2569. if (input != null && input.touchSupported)
  2570. {
  2571. TouchScreenKeyboard.hideInput = shouldHideMobileInput;
  2572. }
  2573. m_Keyboard = (inputType == InputType.Password) ?
  2574. TouchScreenKeyboard.Open(m_Text, keyboardType, false, multiLine, true, false, "", characterLimit) :
  2575. TouchScreenKeyboard.Open(m_Text, keyboardType, inputType == InputType.AutoCorrect, multiLine, false, false, "", characterLimit);
  2576. // If TouchKeyboard doesn't support InPlaceEditing don't call OnFocus as mobile doesn't properly support select all
  2577. // Just set it to the end of the text (where it would move when typing starts)
  2578. if (!m_TouchKeyboardAllowsInPlaceEditing)
  2579. {
  2580. MoveTextEnd(false);
  2581. }
  2582. }
  2583. // Perform normal OnFocus routine if platform supports it
  2584. if (!TouchScreenKeyboard.isSupported || m_TouchKeyboardAllowsInPlaceEditing)
  2585. {
  2586. if (input != null)
  2587. input.imeCompositionMode = IMECompositionMode.On;
  2588. OnFocus();
  2589. }
  2590. m_AllowInput = true;
  2591. m_OriginalText = text;
  2592. m_WasCanceled = false;
  2593. SetCaretVisible();
  2594. UpdateLabel();
  2595. }
  2596. /// <summary>
  2597. /// What to do when the event system sends a submit Event.
  2598. /// </summary>
  2599. /// <param name="eventData">The data on which to process</param>
  2600. public override void OnSelect(BaseEventData eventData)
  2601. {
  2602. base.OnSelect(eventData);
  2603. if (shouldActivateOnSelect)
  2604. ActivateInputField();
  2605. }
  2606. /// <summary>
  2607. /// What to do when the event system sends a pointer click Event
  2608. /// </summary>
  2609. /// <param name="eventData">The data on which to process</param>
  2610. public virtual void OnPointerClick(PointerEventData eventData)
  2611. {
  2612. if (eventData.button != PointerEventData.InputButton.Left)
  2613. return;
  2614. ActivateInputField();
  2615. }
  2616. /// <summary>
  2617. /// Function to deactivate the InputField to stop the processing of Events and send OnSubmit if not canceled.
  2618. /// </summary>
  2619. /// <example>
  2620. /// <code>
  2621. /// using UnityEngine;
  2622. /// using System.Collections;
  2623. /// using UnityEngine.UI; // Required when Using UI elements.
  2624. ///
  2625. /// public class Example : MonoBehaviour
  2626. /// {
  2627. /// public InputField mainInputField;
  2628. ///
  2629. /// // Deactivates the main input field when the scene starts.
  2630. /// void Start()
  2631. /// {
  2632. /// mainInputField.DeactivateInputField();
  2633. /// }
  2634. /// }
  2635. /// </code>
  2636. /// </example>
  2637. public void DeactivateInputField()
  2638. {
  2639. // Not activated do nothing.
  2640. if (!m_AllowInput)
  2641. return;
  2642. m_HasDoneFocusTransition = false;
  2643. m_AllowInput = false;
  2644. if (m_Placeholder != null)
  2645. m_Placeholder.enabled = string.IsNullOrEmpty(m_Text);
  2646. if (m_TextComponent != null && IsInteractable())
  2647. {
  2648. if (m_WasCanceled)
  2649. text = m_OriginalText;
  2650. SendOnSubmit();
  2651. if (m_Keyboard != null)
  2652. {
  2653. m_Keyboard.active = false;
  2654. m_Keyboard = null;
  2655. }
  2656. m_CaretPosition = m_CaretSelectPosition = 0;
  2657. if (input != null)
  2658. input.imeCompositionMode = IMECompositionMode.Auto;
  2659. }
  2660. MarkGeometryAsDirty();
  2661. }
  2662. /// <summary>
  2663. /// What to do when the event system sends a Deselect Event. Defaults to deactivating the inputfield.
  2664. /// </summary>
  2665. /// <param name="eventData">The data sent by the EventSystem</param>
  2666. public override void OnDeselect(BaseEventData eventData)
  2667. {
  2668. DeactivateInputField();
  2669. base.OnDeselect(eventData);
  2670. }
  2671. public virtual void OnSubmit(BaseEventData eventData)
  2672. {
  2673. if (!IsActive() || !IsInteractable())
  2674. return;
  2675. if (!isFocused)
  2676. m_ShouldActivateNextUpdate = true;
  2677. }
  2678. private void EnforceContentType()
  2679. {
  2680. switch (contentType)
  2681. {
  2682. case ContentType.Standard:
  2683. {
  2684. // Don't enforce line type for this content type.
  2685. m_InputType = InputType.Standard;
  2686. m_KeyboardType = TouchScreenKeyboardType.Default;
  2687. m_CharacterValidation = CharacterValidation.None;
  2688. break;
  2689. }
  2690. case ContentType.Autocorrected:
  2691. {
  2692. // Don't enforce line type for this content type.
  2693. m_InputType = InputType.AutoCorrect;
  2694. m_KeyboardType = TouchScreenKeyboardType.Default;
  2695. m_CharacterValidation = CharacterValidation.None;
  2696. break;
  2697. }
  2698. case ContentType.IntegerNumber:
  2699. {
  2700. m_LineType = LineType.SingleLine;
  2701. m_InputType = InputType.Standard;
  2702. m_KeyboardType = TouchScreenKeyboardType.NumberPad;
  2703. m_CharacterValidation = CharacterValidation.Integer;
  2704. break;
  2705. }
  2706. case ContentType.DecimalNumber:
  2707. {
  2708. m_LineType = LineType.SingleLine;
  2709. m_InputType = InputType.Standard;
  2710. m_KeyboardType = TouchScreenKeyboardType.NumbersAndPunctuation;
  2711. m_CharacterValidation = CharacterValidation.Decimal;
  2712. break;
  2713. }
  2714. case ContentType.Alphanumeric:
  2715. {
  2716. m_LineType = LineType.SingleLine;
  2717. m_InputType = InputType.Standard;
  2718. m_KeyboardType = TouchScreenKeyboardType.ASCIICapable;
  2719. m_CharacterValidation = CharacterValidation.Alphanumeric;
  2720. break;
  2721. }
  2722. case ContentType.Name:
  2723. {
  2724. m_LineType = LineType.SingleLine;
  2725. m_InputType = InputType.Standard;
  2726. m_KeyboardType = TouchScreenKeyboardType.NamePhonePad;
  2727. m_CharacterValidation = CharacterValidation.Name;
  2728. break;
  2729. }
  2730. case ContentType.EmailAddress:
  2731. {
  2732. m_LineType = LineType.SingleLine;
  2733. m_InputType = InputType.Standard;
  2734. m_KeyboardType = TouchScreenKeyboardType.EmailAddress;
  2735. m_CharacterValidation = CharacterValidation.EmailAddress;
  2736. break;
  2737. }
  2738. case ContentType.Password:
  2739. {
  2740. m_LineType = LineType.SingleLine;
  2741. m_InputType = InputType.Password;
  2742. m_KeyboardType = TouchScreenKeyboardType.Default;
  2743. m_CharacterValidation = CharacterValidation.None;
  2744. break;
  2745. }
  2746. case ContentType.Pin:
  2747. {
  2748. m_LineType = LineType.SingleLine;
  2749. m_InputType = InputType.Password;
  2750. m_KeyboardType = TouchScreenKeyboardType.NumberPad;
  2751. m_CharacterValidation = CharacterValidation.Integer;
  2752. break;
  2753. }
  2754. default:
  2755. {
  2756. // Includes Custom type. Nothing should be enforced.
  2757. break;
  2758. }
  2759. }
  2760. EnforceTextHOverflow();
  2761. }
  2762. void EnforceTextHOverflow()
  2763. {
  2764. if (m_TextComponent != null)
  2765. if (multiLine)
  2766. m_TextComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
  2767. else
  2768. m_TextComponent.horizontalOverflow = HorizontalWrapMode.Overflow;
  2769. }
  2770. void SetToCustomIfContentTypeIsNot(params ContentType[] allowedContentTypes)
  2771. {
  2772. if (contentType == ContentType.Custom)
  2773. return;
  2774. for (int i = 0; i < allowedContentTypes.Length; i++)
  2775. if (contentType == allowedContentTypes[i])
  2776. return;
  2777. contentType = ContentType.Custom;
  2778. }
  2779. void SetToCustom()
  2780. {
  2781. if (contentType == ContentType.Custom)
  2782. return;
  2783. contentType = ContentType.Custom;
  2784. }
  2785. protected override void DoStateTransition(SelectionState state, bool instant)
  2786. {
  2787. if (m_HasDoneFocusTransition)
  2788. state = SelectionState.Selected;
  2789. else if (state == SelectionState.Pressed)
  2790. m_HasDoneFocusTransition = true;
  2791. base.DoStateTransition(state, instant);
  2792. }
  2793. /// <summary>
  2794. /// See ILayoutElement.CalculateLayoutInputHorizontal.
  2795. /// </summary>
  2796. public virtual void CalculateLayoutInputHorizontal() {}
  2797. /// <summary>
  2798. /// See ILayoutElement.CalculateLayoutInputVertical.
  2799. /// </summary>
  2800. public virtual void CalculateLayoutInputVertical() {}
  2801. /// <summary>
  2802. /// See ILayoutElement.minWidth.
  2803. /// </summary>
  2804. public virtual float minWidth { get { return 0; } }
  2805. /// <summary>
  2806. /// Get the displayed with of all input characters.
  2807. /// </summary>
  2808. public virtual float preferredWidth
  2809. {
  2810. get
  2811. {
  2812. if (textComponent == null)
  2813. return 0;
  2814. var settings = textComponent.GetGenerationSettings(Vector2.zero);
  2815. return textComponent.cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / textComponent.pixelsPerUnit;
  2816. }
  2817. }
  2818. /// <summary>
  2819. /// See ILayoutElement.flexibleWidth.
  2820. /// </summary>
  2821. public virtual float flexibleWidth { get { return -1; } }
  2822. /// <summary>
  2823. /// See ILayoutElement.minHeight.
  2824. /// </summary>
  2825. public virtual float minHeight { get { return 0; } }
  2826. /// <summary>
  2827. /// Get the height of all the text if constrained to the height of the RectTransform.
  2828. /// </summary>
  2829. public virtual float preferredHeight
  2830. {
  2831. get
  2832. {
  2833. if (textComponent == null)
  2834. return 0;
  2835. var settings = textComponent.GetGenerationSettings(new Vector2(textComponent.rectTransform.rect.size.x, 0.0f));
  2836. return textComponent.cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / textComponent.pixelsPerUnit;
  2837. }
  2838. }
  2839. /// <summary>
  2840. /// See ILayoutElement.flexibleHeight.
  2841. /// </summary>
  2842. public virtual float flexibleHeight { get { return -1; } }
  2843. /// <summary>
  2844. /// See ILayoutElement.layoutPriority.
  2845. /// </summary>
  2846. public virtual int layoutPriority { get { return 1; } }
  2847. }
  2848. }