LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

TextInputElement

Description
Text input element which captures strings from player input. Used layers: "cursor" for a text input cursor icon. TODO: IME property docs
Parent
ButtonElement
XML Configuration Parameters
GuiElement#imeKeyboardTypestring [optional] Input method editor keyboard type, defaults to "normal". TODO: add valid types based on engine code
GuiElement#imeTitlestring
GuiElement#imeDescriptionstring
GuiElement#imePlaceholderstring
GuiElement#maxCharactersint [optional] Maximum number of characters to allow as input, defaults to 512.
GuiElement#maxInputTextWidthstring [optional] Maximum pixel width of input text in reference resolution. Must be defined when text alignment is not "left". Format: "[width]px"
GuiElement#cursorOffsetstring [optional] Pixel offset of input cursor icon in text element in reference resolution, defaults to [0, 0]. Format: "[x]px y[px]"
GuiElement#cursorSizestring [optional] Pixel size of input cursor icon in text element in reference resolution. Format: "[width]px [height]px"
GuiElement#isPasswordbool [optional] If true, will behave as password input and mask characters, defaults to false.

Functions

abortIme

Description
Definition
abortIme()
Code
505function TextInputElement:abortIme()
506 if self.useIme and self.imeActive then
507 self.imeActive = false
508 self.preImeText = ""
509 imeAbort()
510 end
511end

applyScreenAlignment

Description
Definition
applyScreenAlignment()
Code
206function TextInputElement:applyScreenAlignment()
207 self:applyTextInputAspectScale()
208
209 TextInputElement:superClass().applyScreenAlignment(self)
210end

applyTextInputAspectScale

Description
Definition
applyTextInputAspectScale()
Code
193function TextInputElement:applyTextInputAspectScale()
194 local xScale, yScale = self:getAspectScale()
195
196 self.cursorOffset[1] = self.cursorOffset[1] * xScale
197 self.cursorSize[1] = self.cursorSize[1] * xScale
198 self.maxInputTextWidth = self.maxInputTextWidth * xScale
199
200 self.cursorOffset[2] = self.cursorOffset[2] * yScale
201 self.cursorSize[2] = self.cursorSize[2] * yScale
202end

copyAttributes

Description
Definition
copyAttributes()
Code
164function TextInputElement:copyAttributes(src)
165 TextInputElement:superClass().copyAttributes(self, src)
166
167 self.imeKeyboardType = src.imeKeyboardType
168 self.imeTitle = src.imeTitle
169 self.imeDescription = src.imeDescription
170 self.imePlaceholder = src.imePlaceholder
171
172 self.maxCharacters = src.maxCharacters
173 self.maxInputTextWidth = src.maxInputTextWidth
174
175 GuiOverlay.copyOverlay(self.cursor, src.cursor)
176 self.cursorOffset = table.copy(src.cursorOffset)
177 self.cursorSize = table.copy(src.cursorSize)
178 self.isPassword = src.isPassword
179
180 self.onEnterCallback = src.onEnterCallback
181 self.onTextChangedCallback = src.onTextChangedCallback
182 self.onEnterPressedCallback = src.onEnterPressedCallback
183 self.onEscPressedCallback = src.onEscPressedCallback
184 self.onIsUnicodeAllowedCallback = src.onIsUnicodeAllowedCallback
185
186 self.enterWhenClickOutside = src.enterWhenClickOutside
187
188 self:finalize()
189end

delete

Description
Definition
delete()
Code
88function TextInputElement:delete()
89 self:abortIme()
90 GuiOverlay.deleteOverlay(self.cursor)
91 TextInputElement:superClass().delete(self)
92end

deleteText

Description
Definition
deleteText()
Code
445function TextInputElement:deleteText(deleteRightCharacterFromCursor)
446 local textLength = utf8Strlen(self.text)
447
448 if textLength > 0 then
449 local canDelete = false
450 local deleteOffset
451
452 if deleteRightCharacterFromCursor then
453 if self.cursorPosition <= textLength then
454 canDelete = true
455 deleteOffset = 0
456 end
457 else
458 if self.cursorPosition > 1 then
459 canDelete = true
460 deleteOffset = -1
461 end
462 end
463
464 if canDelete then
465 --[[
466 print(string.format(
467 "self.cursorPosition %d, deleteOffset %d, textLength %d, prestring : %s, poststring : %s",
468 self.cursorPosition, deleteOffset, textLength,
469 tostring(utf8Substr(self.text, 0, self.cursorPosition + deleteOffset - 1)),
470 tostring(utf8Substr(self.text, self.cursorPosition + deleteOffset, -1))))
471 --]]
472 self.text =
473 (((self.cursorPosition + deleteOffset) > 1) and utf8Substr(self.text, 0, self.cursorPosition + deleteOffset - 1) or "") ..
474 (((self.cursorPosition + deleteOffset) < textLength) and utf8Substr(self.text, self.cursorPosition + deleteOffset, -1) or "")
475 self.cursorPosition = self.cursorPosition + deleteOffset
476 --print("final text : " .. self.text)
477
478 self:raiseCallback("onTextChangedCallback", self, self.text)
479 end
480 end
481end

draw

Description
Definition
draw()
Code
693function TextInputElement:draw(clipX1, clipY1, clipX2, clipY2)
694 -- call ancestor drawing functions with empty text:
695 local text = self.text
696 self.text = ""
697 TextInputElement:superClass().draw(self, clipX1, clipY1, clipX2, clipY2)
698 self.text = text
699
700 setTextAlignment(self.textAlignment)
701 local neededWidth = self:getNeededTextWidth()
702
703 local textXPos = self.absPosition[1] + self.textOffset[1]
704 if self.textAlignment == RenderText.ALIGN_CENTER then
705 textXPos = textXPos + (self.maxInputTextWidth * 0.5) - (neededWidth * 0.5)
706 elseif self.textAlignment == RenderText.ALIGN_RIGHT then
707 textXPos = textXPos + self.maxInputTextWidth - neededWidth
708 end
709 textXPos = textXPos + (self.size[1]-self.maxInputTextWidth) / 2
710
711 local _, yOffset = self:getTextOffset()
712 local _, yPos = self:getTextPosition(self.text)
713 local textYPos = yPos + yOffset
714
715 if clipX1 ~= nil then
716 setTextClipArea(clipX1, clipY1, clipX2, clipY2)
717 end
718
719 local displacementX = 0
720 if self.areFrontDotsVisible then
721 local additionalDisplacement = self:drawTextPart(self.frontDotsText, textXPos, displacementX, textYPos)
722 displacementX = displacementX + additionalDisplacement
723 end
724 if self.isVisibleTextPart1Visible then
725 local additionalDisplacement = self:drawTextPart(self.visibleTextPart1, textXPos, displacementX, textYPos)
726 displacementX = displacementX + additionalDisplacement
727 end
728 if self.isCursorVisible then
729 local additionalDisplacement = self:drawCursor(textXPos, displacementX, textYPos)
730 displacementX = displacementX + additionalDisplacement
731 end
732 if self.isVisibleTextPart2Visible then
733 local additionalDisplacement = self:drawTextPart(self.visibleTextPart2, textXPos, displacementX, textYPos)
734 displacementX = displacementX + additionalDisplacement
735 end
736
737 if self.areBackDotsVisible then
738 self:drawTextPart(self.backDotsText, textXPos, displacementX, textYPos)
739 end
740
741 setTextBold(false)
742 setTextAlignment(RenderText.ALIGN_LEFT)
743 setTextColor(1, 1, 1, 1)
744
745 if clipX1 ~= nil then
746 setTextClipArea(0, 0, 1, 1)
747 end
748end

drawCursor

Description
Definition
drawCursor()
Code
823function TextInputElement:drawCursor(textXPos, displacementX, textYPos)
824 if self.cursorBlinkTime < self.cursorBlinkInterval then
825 local x = textXPos + displacementX + self.cursorOffset[1]
826 x = math.floor(x * g_screenWidth) * (1 / g_screenWidth)
827 GuiOverlay.renderOverlay(self.cursor, x, textYPos + self.cursorOffset[2], self.cursorSize[1], self.cursorSize[2])
828 end
829
830 return self.cursorNeededSize[1]
831end

drawTextPart

Description
Definition
drawTextPart()
Code
796function TextInputElement:drawTextPart(text, textXPos, displacementX, textYPos)
797 local textWidth = 0
798 if text ~= "" then
799 setTextBold(self.textBold)
800 textWidth = getTextWidth(self.textSize, text)
801 local alignmentDisplacement = 0
802 if self.textAlignment == RenderText.ALIGN_CENTER then
803 alignmentDisplacement = textWidth * 0.5
804 elseif self.textAlignment == RenderText.ALIGN_RIGHT then
805 alignmentDisplacement = textWidth
806 end
807
808 if self.text2Size > 0 then
809 setTextBold(self.text2Bold)
810 setTextColor(unpack(self:getText2Color()))
811 renderText(textXPos + alignmentDisplacement + displacementX + (self.text2Offset[1] - self.textOffset[1]), textYPos + (self.text2Offset[2] - self.textOffset[2]), self.text2Size, text)
812 end
813
814 setTextBold(self.textBold)
815 setTextColor(unpack(self:getTextColor()))
816 renderText(textXPos + alignmentDisplacement + displacementX, textYPos, self.textSize, text)
817 end
818 return textWidth
819end

finalize

Description
Definition
finalize()
Code
214function TextInputElement:finalize()
215 self.cursorNeededSize = {
216 self.cursorOffset[1] + self.cursorSize[1],
217 self.cursorOffset[2] + self.cursorSize[2]
218 }
219
220 if not self.maxInputTextWidth and (self.textAlignment == RenderText.ALIGN_CENTER or self.textAlignment == RenderText.ALIGN_RIGHT) then
221 Logging.error('TextInputElement loading using "center" or "right" alignment requires specification of "maxInputTextWidth"')
222 end
223
224 if self.maxInputTextWidth and self.maxInputTextWidth <= (getTextWidth(self.textSize, self.frontDotsText) + self.cursorNeededSize[1] + getTextWidth(self.textSize, self.backDotsText)) then
225 Logging.warning('TextInputElement loading specified "maxInputTextWidth" is too small (%.4f) to display needed data', self.maxInputTextWidth)
226 end
227end

getAvailableTextWidth

Description
Definition
getAvailableTextWidth()
Code
1008function TextInputElement:getAvailableTextWidth()
1009 if not self.maxInputTextWidth then
1010 return nil
1011 end
1012
1013 local availableTextWidth = self.maxInputTextWidth
1014
1015 if self.areFrontDotsVisible then
1016 availableTextWidth = availableTextWidth - getTextWidth(self.textSize, self.frontDotsText)
1017 end
1018
1019 if self.isCursorVisible then
1020 availableTextWidth = availableTextWidth - self.cursorNeededSize[1]
1021 end
1022
1023 if self.areBackDotsVisible then
1024 availableTextWidth = availableTextWidth - getTextWidth(self.textSize, self.backDotsText)
1025 end
1026
1027 return availableTextWidth
1028end

getDoRenderText

Description
Definition
getDoRenderText()
Code
290function TextInputElement:getDoRenderText()
291 return false
292end

getIsActive

Description
Definition
getIsActive()
Code
231function TextInputElement:getIsActive()
232 return GuiElement.getIsActive(self) -- parent type ButtonElement behaves incompatibly, use the base method
233end

getIsUnicodeAllowed

Description
Definition
getIsUnicodeAllowed()
Code
352function TextInputElement:getIsUnicodeAllowed(unicode)
353 if unicode == 13 or unicode == 10 then
354 return false
355 end
356 if not getCanRenderUnicode(unicode) then
357 return false
358 end
359
360 return Utils.getNoNil(self:raiseCallback("onIsUnicodeAllowedCallback", unicode), true)
361end

getNeededTextWidth

Description
Definition
getNeededTextWidth()
Code
1032function TextInputElement:getNeededTextWidth()
1033 local neededWidth = 0
1034 if self.areFrontDotsVisible then
1035 neededWidth = neededWidth + getTextWidth(self.textSize, self.frontDotsText)
1036 end
1037
1038 if self.isVisibleTextPart1Visible then
1039 neededWidth = neededWidth + getTextWidth(self.textSize, self.visibleTextPart1)
1040 end
1041
1042 if self.isCursorVisible then
1043 neededWidth = neededWidth + self.cursorNeededSize[1]
1044 end
1045
1046 if self.isVisibleTextPart2Visible then
1047 neededWidth = neededWidth + getTextWidth(self.textSize, self.visibleTextPart2)
1048 end
1049
1050 if self.areBackDotsVisible then
1051 neededWidth = neededWidth + getTextWidth(self.textSize, self.backDotsText)
1052 end
1053
1054 return neededWidth
1055end

getText

Description
Get text
Definition
getText()
Code
1059function TextInputElement:getText()
1060 return self.text
1061end

inputEvent

Description
Handle GUI input events. Reacts to confirmation and cancel actions. Also see GuiElement.inputEvent().
Definition
inputEvent()
Code
609function TextInputElement:inputEvent(action, value, eventUsed)
610 -- break inheritance from ButtonElement, text input needs custom logic
611 if self.blockTime <= 0 then
612 if not self.imeActive and self:getIsActive() and self:getOverlayState() == GuiOverlay.STATE_PRESSED then
613 if action == InputAction.MENU_ACCEPT then
614 if self.forcePressed then
615 self:setForcePressed(false)
616 else
617 self:setForcePressed(true)
618 end
619 self:raiseCallback("onEnterPressedCallback", self)
620 eventUsed = true
621 elseif action == InputAction.MENU_CANCEL or action == InputAction.MENU_BACK then
622 if self.forcePressed then
623 self:setForcePressed(false)
624 else
625 self:setForcePressed(true)
626 end
627 self:raiseCallback("onEscPressedCallback", self)
628 eventUsed = true
629 end
630 end
631 end
632
633 return eventUsed
634end

keyEvent

Description
Definition
keyEvent()
Code
515function TextInputElement:keyEvent(unicode, sym, modifier, isDown, eventUsed)
516 if TextInputElement:superClass().keyEvent(self, unicode, sym, modifier, isDown, eventUsed) then
517 eventUsed = true
518 end
519
520 if self.isRepeatingSpecialKeyDown and not isDown and self.repeatingSpecialKeySym == sym then
521 self:stopSpecialKeyRepeating()
522 end
523
524 if self.blockTime <= 0 and self:getIsActive() and self:getOverlayState() == GuiOverlay.STATE_PRESSED then
525 local wasSpecialKey = false
526
527 if not isDown then
528 -- react to input state-changing keys on key "up" to avoid double inputs in the menu
529 if sym == Input.KEY_return and self.isReturnDown then
530 self.isReturnDown = false
531 self:setForcePressed(not self.forcePressed)
532 self:raiseCallback("onEnterPressedCallback", self)
533 elseif sym == Input.KEY_esc then
534 self.isEscDown = false
535 self:setForcePressed(not self.forcePressed)
536 self:raiseCallback("onEscPressedCallback", self)
537 end
538 else
539 local startSpecialKeyRepeating = false
540 if sym == Input.KEY_left then
541 --self.cursorPosition = math.max(1, self.cursorPosition - 1)
542 -- is now handled by Focus system
543 self:moveCursorLeft()
544 startSpecialKeyRepeating = true
545 wasSpecialKey = true
546 elseif sym == Input.KEY_right then
547 --self.cursorPosition = math.min(utf8Strlen(self.text) + 1, self.cursorPosition + 1)
548 -- is now handled by focus system
549 self:moveCursorRight()
550 startSpecialKeyRepeating = true
551 wasSpecialKey = true
552 elseif sym == Input.KEY_home then
553 self.cursorPosition = 1
554 wasSpecialKey = true
555 elseif sym == Input.KEY_end then
556 self.cursorPosition = utf8Strlen(self.text) + 1
557 wasSpecialKey = true
558 elseif sym == Input.KEY_delete then
559 self:deleteText(true)
560 startSpecialKeyRepeating = true
561 wasSpecialKey = true
562 elseif sym == Input.KEY_backspace then
563 self:deleteText(false)
564 startSpecialKeyRepeating = true
565 wasSpecialKey = true
566 elseif sym == Input.KEY_esc then
567 self.isEscDown = true
568 wasSpecialKey = true
569 elseif sym == Input.KEY_return then
570 self.isReturnDown = true
571 wasSpecialKey = true
572 end
573
574 if startSpecialKeyRepeating then
575 self.isRepeatingSpecialKeyDown = true
576 self.repeatingSpecialKeySym = sym
577 self.repeatingSpecialKeyDelayTime = TextInputElement.INITIAL_REPEAT_DELAY
578 self.repeatingSpecialKeyRemainingDelayTime = self.repeatingSpecialKeyDelayTime
579 end
580
581 if not wasSpecialKey then
582 if self:getIsUnicodeAllowed(unicode) then
583 local textLength = utf8Strlen(self.text)
584 if self.maxCharacters == nil or textLength < self.maxCharacters then
585 self.text =
586 ((self.cursorPosition > 1) and utf8Substr(self.text, 0, self.cursorPosition - 1) or "") ..
587 unicodeToUtf8(unicode) ..
588 ((self.cursorPosition <= textLength) and utf8Substr(self.text, self.cursorPosition - 1) or "")
589
590 self.cursorPosition = self.cursorPosition + 1
591
592 self:raiseCallback("onTextChangedCallback", self, self.text)
593 end
594 end
595 end
596
597 self:updateVisibleTextElements()
598
599 eventUsed = true
600 end
601 end
602
603 return eventUsed
604end

limitTextToAvailableWidth

Description
Definition
limitTextToAvailableWidth()
Code
978function TextInputElement.limitTextToAvailableWidth(text, textSize, availableWidth, trimFront)
979 local resultingText = text
980 local indexOfFirstCharacter = 0
981 local indexOfLastCharacter = utf8Strlen(text)
982
983 if availableWidth then
984 if trimFront then
985 while getTextWidth(textSize, resultingText) > availableWidth do
986 --print("1a limiting text : " .. resultingText)
987 resultingText = utf8Substr(resultingText, 1)
988 indexOfFirstCharacter = indexOfFirstCharacter + 1
989 --print("1b limiting text : " .. resultingText)
990 end
991 else
992 local textLength = utf8Strlen(resultingText)
993 while getTextWidth(textSize, resultingText) > availableWidth do
994 --print("2a limiting text : " .. resultingText)
995 textLength = textLength - 1
996 resultingText = utf8Substr(resultingText, 0, textLength)
997 indexOfLastCharacter = indexOfLastCharacter - 1
998 --print("2b limiting text : " .. resultingText)
999 end
1000 end
1001 end
1002
1003 return resultingText, indexOfFirstCharacter, indexOfLastCharacter
1004end

loadFromXML

Description
Definition
loadFromXML()
Code
105function TextInputElement:loadFromXML(xmlFile, key)
106 TextInputElement:superClass().loadFromXML(self, xmlFile, key)
107
108 self:addCallback(xmlFile, key.."#onEnter", "onEnterCallback")
109 self:addCallback(xmlFile, key.."#onTextChanged", "onTextChangedCallback")
110 self:addCallback(xmlFile, key.."#onEnterPressed", "onEnterPressedCallback")
111 self:addCallback(xmlFile, key.."#onEscPressed", "onEscPressedCallback")
112 self:addCallback(xmlFile, key.."#onIsUnicodeAllowed", "onIsUnicodeAllowedCallback")
113
114 self.imeKeyboardType = Utils.getNoNil(getXMLString(xmlFile, key.."#imeKeyboardType"), self.imeKeyboardType)
115 self.imeTitle = self:translate(getXMLString(xmlFile, key.."#imeTitle"))
116 self.imeDescription = self:translate(getXMLString(xmlFile, key.."#imeDescription"))
117 self.imePlaceholder = self:translate(getXMLString(xmlFile, key.."#imePlaceholder"))
118
119 self.maxCharacters = Utils.getNoNil(getXMLInt(xmlFile, key.."#maxCharacters"), self.maxCharacters)
120 self.maxInputTextWidth = unpack(GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#maxInputTextWidth"), {self.outputSize[1]}, {self.maxInputTextWidth}))
121 self.cursorOffset = GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#cursorOffset"), self.outputSize, self.cursorOffset)
122 self.cursorSize = GuiUtils.getNormalizedValues(getXMLString(xmlFile, key.."#cursorSize"), self.outputSize, self.cursorSize)
123
124 if g_screenWidth > 1 then
125 self.cursorSize[1] = math.max(self.cursorSize[1], 1 / g_screenWidth)
126 end
127
128 self.enterWhenClickOutside = Utils.getNoNil(getXMLBool(xmlFile, key .. "#enterWhenClickOutside"), self.enterWhenClickOutside)
129
130 GuiOverlay.loadOverlay(self, self.cursor, "cursor", self.imageSize, nil, xmlFile, key)
131 GuiOverlay.createOverlay(self.cursor)
132
133 self.isPassword = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isPassword"), self.isPassword)
134
135 self:finalize()
136end

loadProfile

Description
Definition
loadProfile()
Code
140function TextInputElement:loadProfile(profile, applyProfile)
141 TextInputElement:superClass().loadProfile(self, profile, applyProfile)
142
143 self.maxCharacters = profile:getNumber("maxCharacters", self.maxCharacters)
144 self.maxInputTextWidth = unpack(GuiUtils.getNormalizedValues(profile:getValue("maxInputTextWidth"), {self.outputSize[1]}, {self.maxInputTextWidth}))
145 self.cursorOffset = GuiUtils.getNormalizedValues(profile:getValue("cursorOffset"), self.outputSize, self.cursorOffset)
146 self.cursorSize = GuiUtils.getNormalizedValues(profile:getValue("cursorSize"), self.outputSize, self.cursorSize)
147 self.isPassword = profile:getBool("isPassword", self.isPassword)
148
149 GuiOverlay.loadOverlay(self, self.cursor, "cursor", self.imageSize, profile, nil, nil)
150
151 if g_screenWidth > 1 then
152 self.cursorSize[1] = math.max(self.cursorSize[1], 1 / g_screenWidth)
153 end
154
155 if applyProfile then
156 self:applyTextInputAspectScale()
157 end
158
159 self:finalize()
160end

mouseEvent

Description
Definition
mouseEvent()
Code
365function TextInputElement:mouseEvent(posX, posY, isDown, isUp, button, eventUsed)
366 if self:getIsActive() then
367 local isCursorInside = GuiUtils.checkOverlayOverlap(posX, posY, self.absPosition[1], self.absPosition[2], self.size[1], self.size[2])
368
369 if not self.forcePressed then
370 if eventUsed then
371 self:setOverlayState(GuiOverlay.STATE_NORMAL)
372 end
373
374 if not eventUsed and isCursorInside and not FocusManager:isLocked() then
375 FocusManager:setHighlight(self)
376
377 eventUsed = true
378 if self:getOverlayState() == GuiOverlay.STATE_NORMAL then
379 self:setOverlayState(GuiOverlay.STATE_FOCUSED)
380 end
381
382 if isDown and button == Input.MOUSE_BUTTON_LEFT then
383 self.textInputMouseDown = true
384
385 if not self.useIme then
386 self:setOverlayState(GuiOverlay.STATE_PRESSED)
387 end
388 end
389
390 if isUp and button == Input.MOUSE_BUTTON_LEFT and self.textInputMouseDown then
391 self.textInputMouseDown = false
392
393 self:setOverlayState(GuiOverlay.STATE_PRESSED)
394 self:setForcePressed(true)
395 if self.useIme then
396 self:openIme()
397 end
398 end
399 else
400 if (isDown and button == Input.MOUSE_BUTTON_LEFT) or self.textInputMouseDown or self:getOverlayState() ~= GuiOverlay.STATE_PRESSED then
401 FocusManager:unsetHighlight(self)
402 end
403
404 self.textInputMouseDown = false
405 end
406 elseif self.enterWhenClickOutside then
407 if not isCursorInside and isUp and button == Input.MOUSE_BUTTON_LEFT then
408 -- Dismiss when clicking outside of the box
409 self:abortIme()
410 self:setForcePressed(false)
411
412
413 self:raiseCallback("onEnterPressedCallback", self, true)
414 end
415 end
416
417 if not eventUsed then
418 eventUsed = TextInputElement:superClass().mouseEvent(self, posX, posY, isDown, isUp, button, eventUsed)
419 end
420 end
421
422 return eventUsed
423end

moveCursorLeft

Description
Definition
moveCursorLeft()
Code
427function TextInputElement:moveCursorLeft()
428 self:setCursorPosition(self.cursorPosition - 1)
429end

moveCursorRight

Description
Definition
moveCursorRight()
Code
433function TextInputElement:moveCursorRight()
434 self:setCursorPosition(self.cursorPosition + 1)
435end

new

Description
Definition
new()
Code
38function TextInputElement.new(target, custom_mt)
39 local self = ButtonElement.new(target, custom_mt or TextInputElement_mt)
40
41 self.textInputMouseDown = false
42 self.forcePressed = false
43 self.isPassword = false
44 self.displayText = "" -- actually displayed text, masked if this is a password input field
45 self.cursor = {}
46 self.cursorBlinkTime = 0
47 self.cursorBlinkInterval = 400
48 self.cursorOffset = {0,0}
49 self.cursorSize = {0.0016, 0.018}
50 self.cursorNeededSize = {
51 self.cursorOffset[1] + self.cursorSize[1],
52 self.cursorOffset[2] + self.cursorSize[2]
53 }
54 self.cursorPosition = 1
55 self.firstVisibleCharacterPosition = 1
56 self.lastVisibleCharacterPosition = 1
57 self.maxCharacters = nil
58 self.maxInputTextWidth = nil
59 self.frontDotsText = "..."
60 self.backDotsText = "..."
61 self.text = ""
62 self.useIme = imeIsSupported()
63 self.preImeText = ""
64 self.imeActive = false
65 self.blockTime = 0
66
67 self.isReturnDown = false
68 self.isEscDown = false
69 self.isCapturingInput = false
70 self.hadFocusOnCapture = false
71 self.enterWhenClickOutside = true
72
73 -- Handle hightlight on focused elements differently: if highlight is removed,
74 -- do not change focus.
75 self.disallowFocusedHighlight = true
76
77 self.imeKeyboardType = "normal"
78
79 self.forceFocus = true
80
81 self.customFocusSample = GuiSoundPlayer.SOUND_SAMPLES.TEXTBOX
82
83 return self
84end

onClose

Description
Definition
onClose()
Code
787function TextInputElement:onClose()
788 TextInputElement:superClass().onClose(self)
789 -- makes sure that the input mode is disabled when clicking directly on a "back" button while text input is active
790 self:abortIme()
791 self:setForcePressed(false)
792end

onFocusActivate

Description
Definition
onFocusActivate()
Code
767function TextInputElement:onFocusActivate()
768 if self.blockTime <= 0 then
769 TextInputElement:superClass().onFocusActivate(self)
770 self:raiseCallback("onEnterCallback", self)
771
772 if self.forcePressed then
773 self:abortIme()
774 -- deactivate input
775 self:setForcePressed(false)
776 self:setOverlayState(TextInputElement.STATE_FOCUSED)
777 self:raiseCallback("onEnterPressedCallback", self)
778 else
779 self:openIme()
780 self:setForcePressed(true)
781 end
782 end
783end

onFocusLeave

Description
Definition
onFocusLeave()
Code
759function TextInputElement:onFocusLeave()
760 self:abortIme()
761 self:setForcePressed(false)
762 TextInputElement:superClass().onFocusLeave(self)
763end

openIme

Description
Definition
openIme()
Code
494function TextInputElement:openIme()
495 if self.useIme and imeOpen(self.text, self.imeTitle or "", self.imeDescription or "", self.imePlaceholder or "", self.imeKeyboardType or "normal", Utils.getNoNil(self.maxCharacters, 512), self.absPosition[1], self.absPosition[2], self.size[1], self.size[2]) then
496 self.imeActive = true
497 self.preImeText = self.text
498 return true
499 end
500 return false
501end

reset

Description
Definition
reset()
Code
296function TextInputElement:reset()
297 TextInputElement:superClass().reset(self)
298
299 if self.isRepeatingSpecialKeyDown then
300 self:stopSpecialKeyRepeating()
301 end
302end

setAlpha

Description
Definition
setAlpha()
Code
281function TextInputElement:setAlpha(alpha)
282 TextInputElement:superClass().setAlpha(self, alpha)
283 if self.cursor ~= nil then
284 self.cursor.alpha = self.alpha
285 end
286end

setCaptureInput

Description
Set input capturing state. When capturing, the standard input bindings are disabled (input context switch).
Definition
setCaptureInput()
Code
238function TextInputElement:setCaptureInput(isCapturing)
239 self.blockTime = 200
240 if not self.isCapturingInput and isCapturing then
241 -- reset control key flags to avoid immediately returning out of edit mode:
242 self.isReturnDown = false
243 self.isEscDown = false
244
245 self.target:disableInputForDuration(0)
246
247 if TextInputElement.inputContextActive then
248 -- Special case handling for mouse click activation of text input elements. Because of the call order,
249 -- another text element may previously have been active when this one has been activated by click. Avoid
250 -- corrupting the input context by reverting here first.
251 g_inputBinding:revertContext(true)
252 end
253
254 g_inputBinding:setContext(TextInputElement.INPUT_CONTEXT_NAME, true, false)
255 TextInputElement.inputContextActive = true
256
257 if not GS_IS_CONSOLE_VERSION then
258 -- Special case handling for gaming stations which do not have keyboards available for players:
259 -- Register menu back and accept actions so players can exit text boxes with gamepads using either input,
260 -- by default bound to buttons "A" for accept and "B" for back.
261 g_inputBinding:registerActionEvent(InputAction.MENU_BACK, self, self.inputEvent, false, true, false, true)
262 g_inputBinding:registerActionEvent(InputAction.MENU_ACCEPT, self, self.inputEvent, false, true, false, true)
263 end
264
265 self.isCapturingInput = true
266 elseif self.isCapturingInput and not isCapturing then
267 if TextInputElement.inputContextActive then
268 -- Special case handling for mouse click activation of text input elements. Ensure to avoid double reverts
269 -- when switching from one text input to another.
270 g_inputBinding:revertContext(true) -- revert and clear text input context
271 TextInputElement.inputContextActive = false
272 end
273
274 self.target:disableInputForDuration(200)
275 self.isCapturingInput = false
276 end
277end

setCursorPosition

Description
Definition
setCursorPosition()
Code
439function TextInputElement:setCursorPosition(position)
440 self.cursorPosition = math.max(1, math.min(utf8Strlen(self.text) + 1, position))
441end

setForcePressed

Description
Definition
setForcePressed()
Code
321function TextInputElement:setForcePressed(force)
322 if force then
323 self.hadFocusOnCapture = self:getOverlayState() == GuiOverlay.STATE_FOCUSED
324 self:setCaptureInput(true)
325 else
326 self:setCaptureInput(false)
327 end
328
329 self.forcePressed = force
330 if self.forcePressed then
331 FocusManager:setFocus(self)
332 self:setOverlayState(GuiOverlay.STATE_PRESSED)
333 else
334 local newState = GuiOverlay.STATE_NORMAL
335 if self.hadFocusOnCapture then
336 newState = GuiOverlay.STATE_FOCUSED
337 self.hadFocusOnCapture = false
338 end
339
340 self:setOverlayState(newState)
341 end
342
343 if self.isRepeatingSpecialKeyDown then
344 self:stopSpecialKeyRepeating()
345 end
346
347 self:updateVisibleTextElements()
348end

setText

Description
Definition
setText()
Code
306function TextInputElement:setText(text)
307 local textLength = utf8Strlen(text)
308 if self.maxCharacters and textLength > self.maxCharacters then
309 text = utf8Substr(text, 0, self.maxCharacters)
310 textLength = utf8Strlen(text)
311 end
312
313 TextInputElement:superClass().setText(self, text)
314
315 self.cursorPosition = textLength + 1
316 self:updateVisibleTextElements()
317end

shouldFocusChange

Description
Focus methods
Definition
shouldFocusChange()
Code
753function TextInputElement:shouldFocusChange(direction)
754 return not self.forcePressed
755end

stopSpecialKeyRepeating

Description
Definition
stopSpecialKeyRepeating()
Code
485function TextInputElement:stopSpecialKeyRepeating()
486 self.isRepeatingSpecialKeyDown = false
487 self.repeatingSpecialKeySym = nil
488 self.repeatingSpecialKeyDelayTime = nil
489 self.repeatingSpecialKeyRemainingDelayTime = nil
490end

translate

Description
Definition
translate()
Code
96function TextInputElement:translate(str)
97 if str then
98 str = g_i18n:convertText(str)
99 end
100 return str
101end

update

Description
Definition
update()
Code
638function TextInputElement:update(dt)
639 TextInputElement:superClass().update(self, dt)
640
641 self.cursorBlinkTime = self.cursorBlinkTime+dt
642 while self.cursorBlinkTime > 2*self.cursorBlinkInterval do
643 self.cursorBlinkTime = self.cursorBlinkTime - 2*self.cursorBlinkInterval
644 end
645
646 if self.isRepeatingSpecialKeyDown then
647 self.repeatingSpecialKeyRemainingDelayTime = self.repeatingSpecialKeyRemainingDelayTime - dt
648 if self.repeatingSpecialKeyRemainingDelayTime <= 0 then
649 if self.repeatingSpecialKeySym == Input.KEY_left then
650 self:moveCursorLeft()
651 elseif self.repeatingSpecialKeySym == Input.KEY_right then
652 self:moveCursorRight()
653 elseif self.repeatingSpecialKeySym == Input.KEY_delete then
654 self:deleteText(true)
655 elseif self.repeatingSpecialKeySym == Input.KEY_backspace then
656 self:deleteText(false)
657 end
658 self:updateVisibleTextElements()
659
660 -- reduce key delay each frame down to the minimum to accelerate input when holding control keys
661 self.repeatingSpecialKeyDelayTime = math.max(TextInputElement.MIN_REPEAT_DELAY, (self.repeatingSpecialKeyDelayTime or TextInputElement.INITIAL_REPEAT_DELAY) * (0.1^(dt/100)))
662 self.repeatingSpecialKeyRemainingDelayTime = self.repeatingSpecialKeyDelayTime
663 end
664 end
665 if self.useIme and self.imeActive then
666 local done,cancel = imeIsComplete()
667 if done then
668 self.imeActive = false
669
670 self:setForcePressed(false)
671 if not cancel then
672 self:setText(imeGetLastString())
673 self:raiseCallback("onEnterPressedCallback", self)
674 else
675 self:setText(self.preImeText)
676 self.preImeText = ""
677 self:raiseCallback("onEscPressedCallback", self)
678 end
679 else
680 self:setText(imeGetLastString())
681 self:setCursorPosition(imeGetCursorPos()+1)
682 self:updateVisibleTextElements()
683 end
684 end
685
686 if self.blockTime > 0 then
687 self.blockTime = self.blockTime - dt
688 end
689end

updateVisibleTextElements

Description
Definition
updateVisibleTextElements()
Code
835function TextInputElement:updateVisibleTextElements()
836 self.isCursorVisible = false
837 self.isVisibleTextPart1Visible = false
838 self.visibleTextPart1 = ""
839 self.isVisibleTextPart2Visible = false
840 self.visibleTextPart2 = ""
841
842 self.areFrontDotsVisible = false
843 self.areBackDotsVisible = false
844
845 self.firstVisibleCharacterPosition = 1
846
847 setTextBold(self.textBold)
848
849 local displayText = self.text
850 if self.isPassword then
851 displayText = string.rep("*", utf8Strlen(self.text))
852 end
853
854 local textLength = utf8Strlen(displayText)
855 local availableTextWidth = self:getAvailableTextWidth()
856
857 if self:getIsActive() and self:getOverlayState() == GuiOverlay.STATE_PRESSED then
858 -- input is gathered, cursor is shown,
859 -- text is displayed at an arbitrary position, both additonal text markers may be displayed
860
861 self.isCursorVisible = true
862
863 if self.cursorPosition < self.firstVisibleCharacterPosition then
864 -- cursor was moved to the left to display additional text
865 self.firstVisibleCharacterPosition = self.cursorPosition
866 end
867
868 if self.firstVisibleCharacterPosition > 1 then
869 self.areFrontDotsVisible = true
870 end
871
872 local textInvisibleFrontTrimmed = utf8Substr(displayText, self.firstVisibleCharacterPosition-1)
873 local textWidthInvisibleFrontTrimmed = getTextWidth(self.textSize, textInvisibleFrontTrimmed)
874 availableTextWidth = self:getAvailableTextWidth()
875
876 if availableTextWidth and textWidthInvisibleFrontTrimmed > availableTextWidth then
877 -- not all text fits into the visible area
878 if self.cursorPosition <= textLength then
879 -- the cursor is not at the last position of the text
880 --self.isBackAdditionalTextMarkerVisible = true
881 self.areBackDotsVisible = true
882 availableTextWidth = self:getAvailableTextWidth()
883 end
884 end
885
886
887 local visibleText = TextInputElement.limitTextToAvailableWidth(textInvisibleFrontTrimmed, self.textSize, availableTextWidth)
888 local visibleTextWidth = getTextWidth(self.textSize, visibleText)
889 local visibleTextLength = utf8Strlen(visibleText)
890
891 if availableTextWidth and self.cursorPosition > self.firstVisibleCharacterPosition + visibleTextLength then
892 -- the cursor is on the right side and not visible anymore
893 -- text has to be shifted for the cursor to become visible again
894 --self.isFrontAdditionalTextMarkerVisible = true
895 self.areFrontDotsVisible = true
896 availableTextWidth = self:getAvailableTextWidth()
897
898 local textTrimmedAtCursor = utf8Substr(textInvisibleFrontTrimmed, 0, self.cursorPosition - self.firstVisibleCharacterPosition)
899 visibleText = TextInputElement.limitTextToAvailableWidth(
900 textTrimmedAtCursor, self.textSize, availableTextWidth, true)
901 visibleTextWidth = getTextWidth(self.textSize, visibleText)
902 visibleTextLength = utf8Strlen(visibleText)
903 self.firstVisibleCharacterPosition = self.cursorPosition - visibleTextLength
904 end
905
906 if availableTextWidth and not self.areBackDotsVisible and self.firstVisibleCharacterPosition > 1 then
907 -- check if there is still room for additonal characters (can happen if text gets deleted)
908 local lastCharacterPosition = visibleTextLength + self.firstVisibleCharacterPosition
909 local nextCharacter = utf8Substr(displayText, self.firstVisibleCharacterPosition - 1, 1)
910 local additionalCharacterWidth = getTextWidth(self.textSize, nextCharacter)
911 if visibleTextWidth + additionalCharacterWidth <= availableTextWidth and self.firstVisibleCharacterPosition > 1 then
912 while visibleTextWidth + additionalCharacterWidth <= availableTextWidth and self.firstVisibleCharacterPosition > 1 do
913 -- there is still room for additonal characters
914 self.firstVisibleCharacterPosition = self.firstVisibleCharacterPosition - 1
915 visibleTextWidth = visibleTextWidth + additionalCharacterWidth
916 nextCharacter = utf8Substr(displayText, self.firstVisibleCharacterPosition - 1, 1)
917 additionalCharacterWidth = getTextWidth(self.textSize, nextCharacter)
918 end
919
920 if self.firstVisibleCharacterPosition > 1 then
921 self.areFrontDotsVisible = false
922 local availableWidthWithoutFrontDots = self:getAvailableTextWidth()
923 self.areFrontDotsVisible = true
924 local neededWidthForCompleteText = getTextWidth(self.textSize, displayText)
925 if neededWidthForCompleteText <= availableWidthWithoutFrontDots then
926 self.areFrontDotsVisible = false
927 self.firstVisibleCharacterPosition = 1
928 end
929 else
930 -- all characters are visible
931 self.areFrontDotsVisible = false
932 end
933
934 visibleText = utf8Substr(displayText, self.firstVisibleCharacterPosition - 1, lastCharacterPosition)
935 end
936 end
937
938
939 self.isVisibleTextPart1Visible = true
940 self.visibleTextPart1 = utf8Substr(visibleText, 0, self.cursorPosition - self.firstVisibleCharacterPosition)
941 if visibleTextLength > self.cursorPosition - self.firstVisibleCharacterPosition then
942 self.isVisibleTextPart2Visible = true
943 self.visibleTextPart2 = utf8Substr(visibleText, self.cursorPosition - self.firstVisibleCharacterPosition)
944 end
945
946 else
947 -- input is not gathered, cursor is not shown,
948 -- text is displayed from its beginning, only back additonal text marker may be displayed if text is too long
949 local textWidth = getTextWidth(self.textSize, displayText)
950 -- check if additional text marker has to be displayed
951 if availableTextWidth and textWidth > availableTextWidth then
952 --self.isBackAdditionalTextMarkerVisible = true
953 self.areBackDotsVisible = true
954 availableTextWidth = self:getAvailableTextWidth()
955 end
956
957 -- set visible text
958 if availableTextWidth and textWidth > availableTextWidth then
959 -- not all text fits into the visible area
960 self.visibleTextPart1 = TextInputElement.limitTextToAvailableWidth(displayText, self.textSize, availableTextWidth)
961 self.isVisibleTextPart1Visible = true
962 else
963 -- all text fits into the visible area
964 self.visibleTextPart1 = displayText
965 self.isVisibleTextPart1Visible = true
966 end
967 end
968 setTextBold(false)
969
970 -- print(string.format("updateVisibleTextElements finished :"))
971 -- print(string.format(
972 -- "text: %s - cursorPosition: %d - firstVisibleCharacterPosition: %d - areFrontDotsVisible: %s - isVisibleTextPart1Visible: %s - visibleTextPart1: %s - isCursorVisible: %s - isVisibleTextPart2Visible: %s - visibleTextPart2: %s - areBackDotsVisible: %s",
973 -- self.text, self.cursorPosition, self.firstVisibleCharacterPosition, tostring(self.areFrontDotsVisible), tostring(self.isVisibleTextPart1Visible), self.visibleTextPart1, tostring(self.isCursorVisible), tostring(self.isVisibleTextPart2Visible), self.visibleTextPart2, tostring(self.areBackDotsVisible)))
974end