/ld27

To get this branch, use:
bzr branch /bzr/ld27
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
-- 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

			local frameAction

			for _, key in pairs{'backspace', 'delete', 'left', 'right'} do
				if the.keys:pressed(key) then
					frameAction = key
					if the.keys:alreadyHandled(key) then
						frameAction = 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
}