1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/nuvie/core/nuvie_defs.h"
24
25 #include "ultima/nuvie/gui/gui_text_input.h"
26 #include "ultima/nuvie/gui/gui_font.h"
27 #include "ultima/nuvie/keybinding/keys.h"
28
29 namespace Ultima {
30 namespace Nuvie {
31
GUI_TextInput(int x,int y,uint8 r,uint8 g,uint8 b,const char * str,GUI_Font * gui_font,uint16 width,uint16 height,GUI_CallBack * callback)32 GUI_TextInput:: GUI_TextInput(int x, int y, uint8 r, uint8 g, uint8 b, const char *str,
33 GUI_Font *gui_font, uint16 width, uint16 height, GUI_CallBack *callback)
34 : GUI_Text(x, y, r, g, b, gui_font, width) {
35 max_height = height;
36 callback_object = callback;
37 cursor_color = 0;
38 selected_bgcolor = 0;
39
40 text = (char *)malloc(max_width * max_height + 1);
41
42 if (text == NULL) {
43 DEBUG(0, LEVEL_ERROR, "GUI_TextInput failed to allocate memory for text\n");
44 return;
45 }
46
47 strncpy(text, str, max_width * max_height);
48
49 pos = strlen(text);
50 length = pos;
51
52 area.setWidth(max_width * font->charWidth());
53 area.setHeight(max_height * font->charHeight());
54 }
55
~GUI_TextInput()56 GUI_TextInput::~GUI_TextInput() {
57 return;
58 }
59
release_focus()60 void GUI_TextInput::release_focus() {
61 GUI_Widget::release_focus();
62
63 // SDL_EnableUNICODE(0); //disable unicode.
64 }
65
MouseUp(int x,int y,Shared::MouseButton button)66 GUI_status GUI_TextInput::MouseUp(int x, int y, Shared::MouseButton button) {
67 // if(button == SDL_BUTTON_WHEELUP || button == SDL_BUTTON_WHEELDOWN)
68 // return GUI_PASS;
69 //release focus if we click outside the text box.
70 if (focused && !HitRect(x, y))
71 release_focus();
72 else {
73 if (!focused) {
74 grab_focus();
75 // FIXME SDL2 SDL_EnableUNICODE(1); //turn on unicode processing.
76 }
77 }
78
79 return (GUI_PASS);
80 }
81
KeyDown(const Common::KeyState & keyState)82 GUI_status GUI_TextInput::KeyDown(const Common::KeyState &keyState) {
83 Common::KeyState key = keyState;
84 char ascii = get_ascii_char_from_keysym(key);
85
86 if (!focused)
87 return GUI_PASS;
88
89
90 if (!Common::isPrint(ascii) && key.keycode != Common::KEYCODE_BACKSPACE) {
91 KeyBinder *keybinder = Game::get_game()->get_keybinder();
92 ActionType a = keybinder->get_ActionType(key);
93 switch (keybinder->GetActionKeyType(a)) {
94 case NORTH_KEY:
95 key.keycode = Common::KEYCODE_UP;
96 break;
97 case SOUTH_KEY:
98 key.keycode = Common::KEYCODE_DOWN;
99 break;
100 case WEST_KEY:
101 key.keycode = Common::KEYCODE_LEFT;
102 break;
103 case EAST_KEY:
104 key.keycode = Common::KEYCODE_RIGHT;
105 break;
106 case TOGGLE_CURSOR_KEY:
107 release_focus();
108 return GUI_PASS; // can tab through to SaveDialog
109 case DO_ACTION_KEY:
110 key.keycode = Common::KEYCODE_RETURN;
111 break;
112 case CANCEL_ACTION_KEY:
113 key.keycode = Common::KEYCODE_ESCAPE;
114 break;
115 case HOME_KEY:
116 key.keycode = Common::KEYCODE_HOME;
117 break;
118 case END_KEY:
119 key.keycode = Common::KEYCODE_END;
120 break;
121 default :
122 if (keybinder->handle_always_available_keys(a)) return GUI_YUM;
123 break;
124 }
125 }
126
127 switch (key.keycode) {
128 case Common::KEYCODE_LSHIFT:
129 case Common::KEYCODE_RSHIFT:
130 case Common::KEYCODE_LCTRL:
131 case Common::KEYCODE_RCTRL:
132 case Common::KEYCODE_CAPSLOCK:
133 break;
134
135 case Common::KEYCODE_KP_ENTER:
136 case Common::KEYCODE_RETURN:
137 if (callback_object)
138 callback_object->callback(TEXTINPUT_CB_TEXT_READY, this, text);
139 // falls through
140 case Common::KEYCODE_ESCAPE :
141 release_focus();
142 break;
143
144 case Common::KEYCODE_HOME:
145 pos = 0;
146 break;
147 case Common::KEYCODE_END:
148 pos = length;
149 break;
150
151 case Common::KEYCODE_KP4:
152 case Common::KEYCODE_LEFT:
153 if (pos > 0)
154 pos--;
155 break;
156
157 case Common::KEYCODE_KP6:
158 case Common::KEYCODE_RIGHT:
159 if (pos < length)
160 pos++;
161 break;
162
163 case Common::KEYCODE_DELETE :
164 if (pos < length) { //delete the character to the right of the cursor
165 pos++;
166 remove_char();
167 break;
168 }
169 break;
170
171 case Common::KEYCODE_BACKSPACE :
172 remove_char();
173 break; //delete the character to the left of the cursor
174
175 case Common::KEYCODE_UP:
176 case Common::KEYCODE_KP8:
177 if (pos == length) {
178 if (length + 1 > max_width * max_height)
179 break;
180 length++;
181 if (pos == 0 || text[pos - 1] == ' ')
182 text[pos] = 'A';
183 else
184 text[pos] = 'a';
185 break;
186 }
187 text[pos]++;
188 // We want alphanumeric characters or space
189 if (text[pos] < ' ' || text[pos] > 'z') {
190 text[pos] = ' ';
191 break;
192 }
193 while (!Common::isAlnum(text[pos]))
194 text[pos]++;
195 break;
196
197 case Common::KEYCODE_KP2:
198 case Common::KEYCODE_DOWN:
199 if (pos == length) {
200 if (length + 1 > max_width * max_height)
201 break;
202 length++;
203 if (pos == 0 || text[pos - 1] == ' ')
204 text[pos] = 'Z';
205 else
206 text[pos] = 'z';
207 break;
208 }
209 text[pos]--;
210 // We want alphanumeric characters or space
211 if (text[pos] < ' ' || text[pos] > 'z') {
212 text[pos] = 'z';
213 break;
214 } else if (text[pos] < '0') {
215 text[pos] = ' ';
216 break;
217 }
218 while (!Common::isAlnum(text[pos]))
219 text[pos]--;
220 break;
221
222 default :
223 if (Common::isPrint(ascii))
224 add_char(ascii);
225 break;
226 }
227
228 return (GUI_YUM);
229 }
230
add_char(char c)231 void GUI_TextInput::add_char(char c) {
232 uint16 i;
233
234 if (length + 1 > max_width * max_height)
235 return;
236
237 if (pos < length) { //shuffle chars to the right if required.
238 for (i = length; i > pos; i--)
239 text[i] = text[i - 1];
240 }
241
242 length++;
243
244 text[pos] = c;
245 pos++;
246
247 text[length] = '\0';
248
249 return;
250 }
251
remove_char()252 void GUI_TextInput::remove_char() {
253 uint16 i;
254
255 if (pos == 0)
256 return;
257
258 for (i = pos - 1; i < length; i++)
259 text[i] = text[i + 1];
260
261 pos--;
262 length--;
263
264 return;
265 }
266
set_text(const char * new_text)267 void GUI_TextInput::set_text(const char *new_text) {
268 if (new_text) {
269 strncpy(text, new_text, max_width * max_height);
270
271 pos = strlen(text);
272 length = pos;
273 }
274 }
275
276 /* Map the color to the display */
SetDisplay(Screen * s)277 void GUI_TextInput::SetDisplay(Screen *s) {
278 GUI_Widget::SetDisplay(s);
279 cursor_color = SDL_MapRGB(surface->format, 0xff, 0, 0);
280 selected_bgcolor = SDL_MapRGB(surface->format, 0x5a, 0x6e, 0x91);
281 }
282
283
284 /* Show the widget */
Display(bool full_redraw)285 void GUI_TextInput:: Display(bool full_redraw) {
286 Common::Rect r;
287
288 if (full_redraw && focused) {
289 r = area;
290 SDL_FillRect(surface, &r, selected_bgcolor);
291 }
292
293 GUI_Text::Display(full_redraw);
294
295 if (focused)
296 display_cursor();
297
298 }
299
display_cursor()300 void GUI_TextInput::display_cursor() {
301 Common::Rect r;
302 uint16 x, y;
303 uint16 cw, ch;
304
305 x = pos % max_width;
306 y = pos / max_width;
307
308 cw = font->charWidth();
309 ch = font->charHeight();
310
311 r.left = area.left + x * cw;
312 r.top = area.top + y * ch;
313 r.setWidth(1);
314 r.setHeight(ch);
315
316 SDL_FillRect(surface, &r, cursor_color);
317
318 return;
319 }
320
321 } // End of namespace Nuvie
322 } // End of namespace Ultima
323