/ld28

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