1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
-- Class: TextInput
-- This is like a <Text> object, only it listens to user input and
-- adjusts its text property accordingly.
--
-- Extends:
-- <Text>
--
-- Events:
-- onChange - Occurs when the input's text has changed, either by a
-- user's input or programmtically.
-- onType - Occurs when the input is about to accept input from a key.
-- This event handler is passed the key about to be inserted.
-- If the handler returns false, *not* nil or any other value,
-- then the key is ignored.
TextInput = Text:extend{
text = '',
-- Property: listening
-- Whether the input is currently listening to input.
listening = true,
-- Property: caret
-- This shows the current insert position.
caret = 0,
-- Property: blinkRate
-- How quickly the caret blinks, in seconds.
blinkRate = 0.5,
-- internal property: _blinkTimer
-- Used to keep track of caret blinking.
_blinkTimer = 0,
-- internal property: _repeatKey
-- Used to keep track of what movement key is being held down.
-- internal property: _repeatTimer
-- Used to keep track of how quickly movement keys repeat.
-- internal property: _caretHeight
-- How tall the caret is onscreen, based on the font.
-- internal property: _caretX
-- Where to draw the caret, relative to the sprite's x position.
update = function (self, elapsed)
if self.listening then
-- listen to normal keys
if the.keys.typed ~= '' then
if (self.onType and self:onType(the.keys.typed)) or not self.onType then
self.text = string.sub(self.text, 1, self.caret) .. the.keys.typed
.. string.sub(self.text, self.caret + 1)
self.caret = self.caret + string.len(the.keys.typed)
end
end
if the.keys:justPressed('home') then
self.caret = 0
end
if the.keys:justPressed('end') then
self.caret = string.len(self.text)
end
-- handle movement keys that repeat
-- we have to simulate repeat rates manually :(
local delay, rate = love.keyboard.getKeyRepeat()
local frameAction
for _, key in pairs{'backspace', 'delete', 'left', 'right'} do
if the.keys:pressed(key) then
if self._repeatKey == key then
self._repeatTimer = self._repeatTimer + elapsed
-- if we've made it past the maximum delay, then
-- we reset the timer and take action
if self._repeatTimer > delay + rate then
self._repeatTimer = delay
frameAction = key
end
else
-- we've just started holding down the key
self._repeatKey = key
self._repeatTimer = 0
frameAction = key
end
else
if self._repeatKey == key then
self._repeatKey = nil
end
end
end
if frameAction == 'backspace' and self.caret > 0 then
self.text = string.sub(self.text, 1, self.caret - 1) .. string.sub(self.text, self.caret + 1)
self.caret = self.caret - 1
end
if frameAction == 'delete' and self.caret < string.len(self.text) then
self.text = string.sub(self.text, 1, self.caret) .. string.sub(self.text, self.caret + 2)
end
if frameAction == 'left' and self.caret > 0 then
self.caret = self.caret - 1
end
if frameAction == 'right' and self.caret < string.len(self.text) then
self.caret = self.caret + 1
end
end
-- update caret position
if self._set.caret ~= self.caret and self._fontObj then
self._caretX = self._fontObj:getWidth(string.sub(self.text, 1, self.caret))
self._caretHeight = self._fontObj:getHeight()
self._set.caret = self.caret
end
-- update caret timer
self._blinkTimer = self._blinkTimer + elapsed
if self._blinkTimer > self.blinkRate * 2 then self._blinkTimer = 0 end
-- call onChange handler as needed
if self.text ~= self._set.text then
if self.onChange then self:onChange() end
self._set.text = self.text
end
Text.update(self, elapsed)
end,
draw = function (self, x, y)
if self.visible then
x = x or self.x
y = y or self.y
Text.draw(self, x, y)
-- draw caret
if (self._repeatKey or self._blinkTimer < self.blinkRate) and
(self._caretX and self._caretHeight) then
love.graphics.setLineWidth(1)
love.graphics.line(x + self._caretX, y, x + self._caretX, y + self._caretHeight)
end
end
end
}
|