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