1-- Copyright (C) 2012 Jared Krinke.
2--
3-- This is free software; you can redistribute it and/or
4-- modify it under the terms of the GNU General Public License
5-- as published by the Free Software Foundation; either version 2
6-- of the License, or (at your option) any later version.
7--
8-- This program is distributed in the hope that it will be useful,
9-- but WITHOUT ANY WARRANTY; without even the implied warranty of
10-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11-- GNU General Public License for more details.
12--
13-- You should have received a copy of the GNU General Public License
14-- along with this program; if not, write to the Free Software
15-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17local cursorWidth = 0.3
18local cursorSpace = 0.2
19
20TextInputBox = { }
21
22-- TODO: Command history for console
23function TextInputBox.new(submitted, initialText, maxLength)
24    local textInputBox = Entity.new()
25
26    textInputBox.submitted = submitted
27    textInputBox.buffer = StringBuffer.new()
28    textInputBox.maxLength = maxLength
29    textInputBox.textElement = Element.Text.new()
30    textInputBox.cursor = Element.Image.new("Images/Blank.png", 0, 0.5, -1, cursorWidth, 1, 0, Color.new(1, 1, 1, 0.3))
31    textInputBox.cursorPosition = 1
32
33    function textInputBox.clear(self)
34        self:setCursorPosition(1)
35        self.buffer:clear()
36    end
37
38    function textInputBox.setCursorPosition(self, position)
39        self.cursorPosition = position
40        self.cursor.x = position - (1 - cursorSpace)
41    end
42
43    function textInputBox.append(self, character)
44        if not isNumber(self.maxLength) or #self.buffer.text < self.maxLength then
45            self.buffer:insert(character, self.cursorPosition)
46            self:setCursorPosition(self.cursorPosition + 1)
47        end
48    end
49
50    function textInputBox.backspace(self)
51        if self.cursorPosition > 1 then
52            self.buffer:remove(self.cursorPosition - 1, 1)
53            self:setCursorPosition(self.cursorPosition - 1)
54        end
55    end
56
57    function textInputBox.delete(self)
58        if self.cursorPosition <= self.buffer.length then
59            self.buffer:remove(self.cursorPosition, 1)
60        end
61    end
62
63    function textInputBox.moveLeft(self)
64        if self.cursorPosition > 1 then
65            self:setCursorPosition(self.cursorPosition - 1)
66        end
67    end
68
69    function textInputBox.moveRight(self)
70        if self.cursorPosition <= self.buffer.length then
71            self:setCursorPosition(self.cursorPosition + 1)
72        end
73    end
74
75    function textInputBox.enter(self)
76        if isFunction(self.submitted) then
77            self:submitted()
78        end
79    end
80
81    function textInputBox.keyPressed(self, key, pressed, character)
82        if pressed then
83            local handler = self.handlers[key]
84
85            if isFunction(handler) then
86                handler(self, character)
87            end
88        end
89    end
90
91    function textInputBox.getText(self)
92        return self.buffer.text
93    end
94
95    -- Component methods
96    function textInputBox.setLayer(self, layer)
97        layer:addChild(self)
98    end
99
100    function textInputBox.getPosition(self)
101        return self.x, self.y + self.height
102    end
103
104    function textInputBox.setPosition(self, x, y)
105        self.x = x
106        self.y = y - self.height
107    end
108
109    function textInputBox.setTextSize(self, width, height)
110        self.width = width
111        self.height = height
112    end
113
114    function textInputBox.getMinimumSize(self)
115        -- Leave some minimum amount of space
116        local length = max(#self.buffer.text + 1, 10)
117
118        return length * self.width, self.height
119    end
120
121    textInputBox.getDesiredSize = textInputBox.getMinimumSize
122    textInputBox.getSize = textInputBox.getMinimumSize
123
124    function textInputBox.setSize(self, width, height)
125        -- Ignore size changes other than text size
126    end
127
128    function textInputBox.focused(self)
129        self.cursor.color.opacity = 1
130    end
131
132    function textInputBox.unfocused(self)
133        self.cursor.color.opacity = 0
134    end
135
136    textInputBox.textElement.buffer = textInputBox.buffer
137
138    textInputBox.elements:add(textInputBox.textElement)
139    textInputBox.elements:add(textInputBox.cursor)
140
141    textInputBox.handlers = {
142        ['a'] = textInputBox.append,
143        ['b'] = textInputBox.append,
144        ['c'] = textInputBox.append,
145        ['d'] = textInputBox.append,
146        ['e'] = textInputBox.append,
147        ['f'] = textInputBox.append,
148        ['g'] = textInputBox.append,
149        ['h'] = textInputBox.append,
150        ['i'] = textInputBox.append,
151        ['j'] = textInputBox.append,
152        ['k'] = textInputBox.append,
153        ['l'] = textInputBox.append,
154        ['m'] = textInputBox.append,
155        ['n'] = textInputBox.append,
156        ['o'] = textInputBox.append,
157        ['p'] = textInputBox.append,
158        ['q'] = textInputBox.append,
159        ['r'] = textInputBox.append,
160        ['s'] = textInputBox.append,
161        ['t'] = textInputBox.append,
162        ['u'] = textInputBox.append,
163        ['v'] = textInputBox.append,
164        ['w'] = textInputBox.append,
165        ['x'] = textInputBox.append,
166        ['y'] = textInputBox.append,
167        ['z'] = textInputBox.append,
168        ['0'] = textInputBox.append,
169        ['1'] = textInputBox.append,
170        ['2'] = textInputBox.append,
171        ['3'] = textInputBox.append,
172        ['4'] = textInputBox.append,
173        ['5'] = textInputBox.append,
174        ['6'] = textInputBox.append,
175        ['7'] = textInputBox.append,
176        ['8'] = textInputBox.append,
177        ['9'] = textInputBox.append,
178        ['-'] = textInputBox.append,
179        ['='] = textInputBox.append,
180        ['['] = textInputBox.append,
181        [']'] = textInputBox.append,
182        ['\\'] = textInputBox.append,
183        [';'] = textInputBox.append,
184        ['\''] = textInputBox.append,
185        [','] = textInputBox.append,
186        ['.'] = textInputBox.append,
187        ['/'] = textInputBox.append,
188        ['`'] = textInputBox.append,
189        ["kp-0"] = function(self) self:append("0") end,
190        ["kp-1"] = function(self) self:append("1") end,
191        ["kp-2"] = function(self) self:append("2") end,
192        ["kp-3"] = function(self) self:append("3") end,
193        ["kp-4"] = function(self) self:append("4") end,
194        ["kp-5"] = function(self) self:append("5") end,
195        ["kp-6"] = function(self) self:append("6") end,
196        ["kp-7"] = function(self) self:append("7") end,
197        ["kp-8"] = function(self) self:append("8") end,
198        ["kp-9"] = function(self) self:append("9") end,
199        ["kp-period"] = function(self) self:append(".") end,
200        ["kp-div"] = function(self) self:append("/") end,
201        ["kp-mult"] = function(self) self:append("*") end,
202        ["kp-minus"] = function(self) self:append("-") end,
203        ["kp-plus"] = function(self) self:append("+") end,
204        ["kp-eq"] = function(self) self:append("=") end,
205        ["kp-ent"] = textInputBox.enter,
206        ["space"] = textInputBox.append,
207        ["backspace"] = textInputBox.backspace,
208        ["delete"] = textInputBox.delete,
209        ["left"] = textInputBox.moveLeft,
210        ["right"] = textInputBox.moveRight,
211        ["enter"] = textInputBox.enter,
212        ["escape"] = textInputBox.clear,
213    }
214
215
216    -- Set default text and cursor position
217    if isString(initialText) then
218        textInputBox.buffer:append(initialText)
219        textInputBox:setCursorPosition(#initialText + 1)
220    else
221        textInputBox:setCursorPosition(1)
222    end
223
224    return textInputBox
225end
226
227