/ld26-basecode

To get this branch, use:
bzr branch http://9ix.org/bzr/ld26-basecode

« back to all changes in this revision

Viewing changes to zoetrope/ui/textinput.lua

  • Committer: Josh C
  • Date: 2013-04-23 15:22:15 UTC
  • Revision ID: josh@9ix.org-20130423152215-hacpxl91eiiq2ras
zoetrope 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}