bzr branch
http://9ix.org/bzr/spacey
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 |
} |