|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00033 char text_input_string[MAX_INPUT_STRING]; 00035 int text_input_count; 00037 static int text_input_cursor_pos = 0; 00039 static int text_input_max; 00040 00042 static char text_input_history[MAX_HISTORY_LINES][MAX_INPUT_STRING]; 00046 static size_t text_input_history_pos = 0; 00047 00049 int text_input_string_flag; 00051 int text_input_string_end_flag; 00053 int text_input_string_esc_flag; 00055 uint32 text_input_opened; 00056 00060 int text_input_center_offset() 00061 { 00062 return Bitmaps[BITMAP_LOGIN_INP]->bitmap->w / 2; 00063 } 00064 00071 void text_input_draw_background(SDL_Surface *surface, int x, int y, int bitmap) 00072 { 00073 _BLTFX bltfx; 00074 00075 bltfx.surface = surface; 00076 bltfx.flags = 0; 00077 bltfx.alpha = 0; 00078 sprite_blt(Bitmaps[bitmap], x, y, NULL, &bltfx); 00079 } 00080 00092 void text_input_draw_text(SDL_Surface *surface, int x, int y, int font, const char *text, const char *color_notation, uint64 flags, int bitmap, SDL_Rect *box) 00093 { 00094 if (!box) 00095 { 00096 SDL_Rect box2; 00097 00098 box2.x = 0; 00099 box2.y = 0; 00100 box2.w = Bitmaps[bitmap]->bitmap->w; 00101 box2.h = Bitmaps[bitmap]->bitmap->h; 00102 box = &box2; 00103 } 00104 00105 x += 6 + box->x; 00106 y += box->h / 2 - FONT_HEIGHT(font) / 2 + box->y; 00107 00108 box->w = box->w - 13 - box->x; 00109 box->h = FONT_HEIGHT(font); 00110 box->x = 0; 00111 box->y = 0; 00112 00113 string_blt(surface, font, text, x, y, color_notation, flags | TEXT_WIDTH, box); 00114 } 00115 00127 void text_input_show(SDL_Surface *surface, int x, int y, int font, const char *text, const char *color_notation, uint64 flags, int bitmap, SDL_Rect *box) 00128 { 00129 char buf[HUGE_BUF]; 00130 SDL_Rect box2; 00131 size_t pos = text_input_cursor_pos; 00132 const char *cp = text; 00133 int underscore_width = glyph_get_width(font, '_'); 00134 00135 box2.w = 0; 00136 00137 /* Figure out the width by going backwards. */ 00138 while (pos > 0) 00139 { 00140 /* Reached the maximum yet? */ 00141 if (box2.w + glyph_get_width(font, *(cp + pos)) + underscore_width > Bitmaps[bitmap]->bitmap->w - 13 - (box ? box->x * 2 : 0)) 00142 { 00143 break; 00144 } 00145 00146 blt_character(&font, font, NULL, &box2, cp + pos, NULL, NULL, 0, NULL, NULL); 00147 pos--; 00148 } 00149 00150 /* Adjust the text position if necessary. */ 00151 if (pos) 00152 { 00153 text += pos; 00154 } 00155 00156 /* Draw the background. */ 00157 text_input_draw_background(surface, x, y, bitmap); 00158 strncpy(buf, text, text_input_cursor_pos - pos); 00159 buf[text_input_cursor_pos - pos] = '_'; 00160 buf[text_input_cursor_pos - pos + 1] = '\0'; 00161 00162 if (text + (text_input_cursor_pos - pos)) 00163 { 00164 strcpy(buf + (text_input_cursor_pos - pos + 1), text + (text_input_cursor_pos - pos)); 00165 } 00166 00167 /* Draw the text. */ 00168 text_input_draw_text(surface, x, y, font, buf, color_notation, flags, bitmap, box); 00169 } 00170 00173 void text_input_clear() 00174 { 00175 text_input_string[0] = '\0'; 00176 text_input_count = 0; 00177 text_input_history_pos = 0; 00178 text_input_history[0][0] = '\0'; 00179 text_input_cursor_pos = 0; 00180 text_input_string_flag = 0; 00181 text_input_string_end_flag = 0; 00182 text_input_string_esc_flag = 0; 00183 } 00184 00188 void text_input_open(int maxchar) 00189 { 00190 int interval, delay; 00191 00192 interval = 120 / (setting_get_int(OPT_CAT_CLIENT, OPT_KEY_REPEAT_SPEED) + 1); 00193 delay = interval + 300 / (setting_get_int(OPT_CAT_CLIENT, OPT_KEY_REPEAT_SPEED) + 1); 00194 00195 text_input_clear(); 00196 text_input_max = maxchar; 00197 SDL_EnableKeyRepeat(delay, interval); 00198 00199 if (cpl.input_mode != INPUT_MODE_NUMBER) 00200 { 00201 cpl.inventory_win = IWIN_BELOW; 00202 } 00203 00204 /* Raise the text/number input widget. */ 00205 if (cpl.input_mode == INPUT_MODE_NUMBER) 00206 { 00207 SetPriorityWidget(cur_widget[IN_NUMBER_ID]); 00208 } 00209 else if (cpl.input_mode == INPUT_MODE_CONSOLE) 00210 { 00211 SetPriorityWidget(cur_widget[IN_CONSOLE_ID]); 00212 } 00213 00214 text_input_string_flag = 1; 00215 text_input_opened = SDL_GetTicks(); 00216 } 00217 00221 static void text_input_history_add(const char *text) 00222 { 00223 size_t i; 00224 00225 /* If new line is empty or identical to last inserted one, skip it */ 00226 if (text[0] == '\0' || !strcmp(text_input_history[1], text)) 00227 { 00228 return; 00229 } 00230 00231 /* Shift history lines. */ 00232 for (i = MAX_HISTORY_LINES - 1; i > 1; i--) 00233 { 00234 strncpy(text_input_history[i], text_input_history[i - 1], sizeof(*text_input_history) - 1); 00235 text_input_history[i][sizeof(*text_input_history) - 1] = '\0'; 00236 } 00237 00238 /* Insert new one. */ 00239 strncpy(text_input_history[1], text, sizeof(*text_input_history) - 1); 00240 text_input_history[1][sizeof(*text_input_history) - 1] = '\0'; 00241 /* Clear temporary editing line. */ 00242 text_input_history[0][0] = '\0'; 00243 text_input_history_pos = 0; 00244 } 00245 00248 void text_input_history_clear() 00249 { 00250 size_t i; 00251 00252 for (i = 0; i < MAX_HISTORY_LINES; i++) 00253 { 00254 text_input_history[i][0] = '\0'; 00255 } 00256 00257 text_input_history_pos = 0; 00258 } 00259 00263 void text_input_add_string(const char *text) 00264 { 00265 /* Copy to input buffer. */ 00266 strncpy(text_input_string, text, sizeof(text_input_string) - 1); 00267 text_input_string[sizeof(text_input_string) - 1] = '\0'; 00268 /* Set cursor after inserted text. */ 00269 text_input_cursor_pos = text_input_count = strlen(text); 00270 } 00271 00276 static void text_input_skip_word(int *i, int left) 00277 { 00278 /* Skip whitespace. */ 00279 while (text_input_string[*i] == ' ' && (left ? *i >= 0 : *i < text_input_count)) 00280 { 00281 *i += left ? -1 : 1; 00282 } 00283 00284 /* Skip a word. */ 00285 while (text_input_string[*i] != ' ' && (left ? *i >= 0 : *i < text_input_count)) 00286 { 00287 *i += left ? -1 : 1; 00288 } 00289 } 00290 00295 int text_input_handle(SDL_KeyboardEvent *key) 00296 { 00297 int i; 00298 00299 if (key->type != SDL_KEYDOWN) 00300 { 00301 return 0; 00302 } 00303 00304 if (keybind_command_matches_event("?PASTE", key)) 00305 { 00306 char *clipboard_contents; 00307 00308 clipboard_contents = clipboard_get(); 00309 00310 if (clipboard_contents) 00311 { 00312 strncat(text_input_string, clipboard_contents, sizeof(text_input_string) - text_input_count - 1); 00313 text_input_cursor_pos = text_input_count = strlen(text_input_string); 00314 00315 for (i = 0; i < text_input_count; i++) 00316 { 00317 if (text_input_string[i] < ' ' || text_input_string[i] > '~') 00318 { 00319 text_input_string[i] = ' '; 00320 } 00321 } 00322 00323 free(clipboard_contents); 00324 } 00325 00326 return 1; 00327 } 00328 00329 switch (key->keysym.sym) 00330 { 00331 case SDLK_ESCAPE: 00332 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); 00333 text_input_string_esc_flag = 1; 00334 return 1; 00335 00336 case SDLK_KP_ENTER: 00337 case SDLK_RETURN: 00338 case SDLK_TAB: 00339 if (key->keysym.sym != SDLK_TAB || GameStatus < GAME_STATUS_WAITFORPLAY) 00340 { 00341 SDL_EnableKeyRepeat(0 , SDL_DEFAULT_REPEAT_INTERVAL); 00342 text_input_string_flag = 0; 00343 /* Mark that we've got something here. */ 00344 text_input_string_end_flag = 1; 00345 00346 /* Record this line in input history only if we are in console mode. */ 00347 if (cpl.input_mode == INPUT_MODE_CONSOLE) 00348 { 00349 text_input_history_add(text_input_string); 00350 } 00351 00352 return 1; 00353 } 00354 else if (key->keysym.sym == SDLK_TAB) 00355 { 00356 help_files_struct *help_files_tmp; 00357 int possibilities = 0; 00358 char cmd_buf[MAX_BUF]; 00359 00360 if (text_input_string[0] != '/' || strrchr(text_input_string, ' ')) 00361 { 00362 return 1; 00363 } 00364 00365 for (help_files_tmp = help_files; help_files_tmp; help_files_tmp = help_files_tmp->next) 00366 { 00367 if (strcmp(help_files_tmp->title + strlen(help_files_tmp->title) - 8, " Command")) 00368 { 00369 continue; 00370 } 00371 00372 if (!strncmp(help_files_tmp->helpname, text_input_string + 1, text_input_count - 1)) 00373 { 00374 if ((help_files_tmp->dm_only && !cpl.dm) || !help_files_tmp->autocomplete) 00375 { 00376 continue; 00377 } 00378 00379 if (possibilities == 0) 00380 { 00381 strncpy(cmd_buf, help_files_tmp->helpname, sizeof(cmd_buf)); 00382 } 00383 else 00384 { 00385 if (possibilities == 1) 00386 { 00387 draw_info_format(COLOR_WHITE, "\nMatching commands:\n%s", cmd_buf); 00388 } 00389 00390 draw_info(COLOR_WHITE, help_files_tmp->helpname); 00391 } 00392 00393 possibilities++; 00394 } 00395 } 00396 00397 if (possibilities == 1) 00398 { 00399 snprintf(text_input_string, sizeof(text_input_string), "/%s ", cmd_buf); 00400 text_input_count = text_input_cursor_pos = (int) strlen(text_input_string); 00401 } 00402 00403 return 1; 00404 } 00405 00406 break; 00407 00408 /* Erases the previous character or word if CTRL is pressed. */ 00409 case SDLK_BACKSPACE: 00410 if (text_input_count && text_input_cursor_pos) 00411 { 00412 int ii = text_input_cursor_pos; 00413 00414 /* Where we will end up, by default one character back. */ 00415 i = ii - 1; 00416 00417 if (key->keysym.mod & KMOD_CTRL) 00418 { 00419 text_input_skip_word(&i, 1); 00420 /* We end up at the beginning of the current word. */ 00421 i++; 00422 } 00423 00424 while (ii <= text_input_count) 00425 { 00426 text_input_string[i++] = text_input_string[ii++]; 00427 } 00428 00429 text_input_cursor_pos -= (ii - i); 00430 text_input_count -= (ii - i); 00431 } 00432 00433 return 1; 00434 00435 case SDLK_DELETE: 00436 { 00437 int ii = text_input_cursor_pos; 00438 00439 /* Where we will end up, by default one character ahead. */ 00440 i = ii + 1; 00441 00442 if (ii == text_input_count) 00443 { 00444 return 1; 00445 } 00446 00447 if (key->keysym.mod & KMOD_CTRL) 00448 { 00449 text_input_skip_word(&i, 0); 00450 } 00451 00452 while (i <= text_input_count) 00453 { 00454 text_input_string[ii++] = text_input_string[i++]; 00455 } 00456 00457 text_input_count -= (i - ii); 00458 return 1; 00459 } 00460 00461 /* Shifts a character or a word if CTRL is pressed. */ 00462 case SDLK_LEFT: 00463 if (key->keysym.mod & KMOD_CTRL) 00464 { 00465 i = text_input_cursor_pos - 1; 00466 text_input_skip_word(&i, 1); 00467 /* Places the cursor on the first letter of this word. */ 00468 text_input_cursor_pos = i + 1; 00469 } 00470 else if (text_input_cursor_pos > 0) 00471 { 00472 text_input_cursor_pos--; 00473 } 00474 00475 return 1; 00476 00477 /* Shifts a character or a word if CTRL is pressed. */ 00478 case SDLK_RIGHT: 00479 if (key->keysym.mod & KMOD_CTRL) 00480 { 00481 i = text_input_cursor_pos; 00482 text_input_skip_word(&i, 0); 00483 /* Places the cursor right after the skipped word. */ 00484 text_input_cursor_pos = i; 00485 } 00486 else if (text_input_cursor_pos < text_input_count) 00487 { 00488 text_input_cursor_pos++; 00489 } 00490 00491 return 1; 00492 00493 /* Scroll forward in history. */ 00494 case SDLK_UP: 00495 if (cpl.input_mode == INPUT_MODE_CONSOLE && text_input_history_pos < MAX_HISTORY_LINES - 1 && text_input_history[text_input_history_pos + 1][0]) 00496 { 00497 /* First history line is special, it records what we were 00498 * writing before scrolling back the history; so, by 00499 * returning back to zero, we can continue our editing 00500 * where we left it. */ 00501 if (text_input_history_pos == 0) 00502 { 00503 strncpy(text_input_history[0], text_input_string, text_input_count); 00504 } 00505 00506 text_input_history_pos++; 00507 text_input_add_string(text_input_history[text_input_history_pos]); 00508 } 00509 00510 return 1; 00511 00512 /* Scroll backward in history. */ 00513 case SDLK_DOWN: 00514 if (cpl.input_mode == INPUT_MODE_CONSOLE && text_input_history_pos > 0) 00515 { 00516 text_input_history_pos--; 00517 text_input_add_string(text_input_history[text_input_history_pos]); 00518 } 00519 00520 return 1; 00521 00522 /* Go to the start of the text input. */ 00523 case SDLK_HOME: 00524 text_input_cursor_pos = 0; 00525 return 1; 00526 00527 /* Go to the end of the text input. */ 00528 case SDLK_END: 00529 text_input_cursor_pos = text_input_count; 00530 return 1; 00531 00532 default: 00533 { 00534 char c; 00535 00536 if (text_input_count < text_input_max) 00537 { 00538 c = 0; 00539 00540 /* We want only numbers in number mode - even when shift is held. */ 00541 if (cpl.input_mode == INPUT_MODE_NUMBER) 00542 { 00543 switch (key->keysym.sym) 00544 { 00545 case SDLK_0: 00546 case SDLK_KP0: 00547 c = '0'; 00548 break; 00549 00550 case SDLK_KP1: 00551 case SDLK_1: 00552 c = '1'; 00553 break; 00554 00555 case SDLK_KP2: 00556 case SDLK_2: 00557 c = '2'; 00558 break; 00559 00560 case SDLK_KP3: 00561 case SDLK_3: 00562 c = '3'; 00563 break; 00564 00565 case SDLK_KP4: 00566 case SDLK_4: 00567 c = '4'; 00568 break; 00569 00570 case SDLK_KP5: 00571 case SDLK_5: 00572 c = '5'; 00573 break; 00574 00575 case SDLK_KP6: 00576 case SDLK_6: 00577 c = '6'; 00578 break; 00579 00580 case SDLK_KP7: 00581 case SDLK_7: 00582 c = '7'; 00583 break; 00584 00585 case SDLK_KP8: 00586 case SDLK_8: 00587 c = '8'; 00588 break; 00589 00590 case SDLK_KP9: 00591 case SDLK_9: 00592 c = '9'; 00593 break; 00594 00595 default: 00596 c = 0; 00597 break; 00598 } 00599 00600 if (c) 00601 { 00602 text_input_string[text_input_cursor_pos++] = c; 00603 text_input_count++; 00604 text_input_string[text_input_count] = 0; 00605 return 1; 00606 } 00607 } 00608 else 00609 { 00610 c = key->keysym.unicode & 0xff; 00611 00612 if (c >= 32) 00613 { 00614 if (key->keysym.mod & KMOD_SHIFT) 00615 { 00616 c = toupper(c); 00617 } 00618 00619 i = text_input_count; 00620 00621 while (i >= text_input_cursor_pos) 00622 { 00623 text_input_string[i + 1] = text_input_string[i]; 00624 i--; 00625 } 00626 00627 text_input_string[text_input_cursor_pos] = c; 00628 text_input_cursor_pos++; 00629 text_input_count++; 00630 text_input_string[text_input_count] = 0; 00631 return 1; 00632 } 00633 } 00634 } 00635 00636 break; 00637 } 00638 } 00639 00640 return 0; 00641 }
1.7.4