Atrinik Client 2.5
gui/settings.c
Go to the documentation of this file.
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 static button_struct button_password;
00034 
00036 enum
00037 {
00038     BUTTON_SETTINGS,
00039     BUTTON_KEY_SETTINGS,
00040     BUTTON_LOGOUT,
00041     BUTTON_BACK,
00042 
00043     BUTTON_NUM
00044 };
00045 
00047 static const char *const button_names[BUTTON_NUM] =
00048 {
00049     "Client Settings", "Key Settings", "Logout", "Back to Play"
00050 };
00051 
00053 static uint8 setting_type = SETTING_TYPE_NONE;
00055 static size_t button_selected;
00057 static size_t setting_category_selected;
00059 static uint32 list_row_clicked;
00061 static uint32 list_clicked = 0;
00063 static uint8 setting_keybind_step;
00065 static SDLKey setting_keybind_key;
00067 static SDLMod setting_keybind_mod;
00069 static sint32 setting_keybind_id;
00073 static uint8 setting_password_confirmed;
00074 
00078 static void settings_list_reload(list_struct *list)
00079 {
00080     size_t i;
00081 
00082     /* Clear all the rows. */
00083     list_clear_rows(list);
00084 
00085     /* Settings? */
00086     if (setting_type == SETTING_TYPE_SETTINGS)
00087     {
00088         setting_struct *setting;
00089 
00090         for (i = 0; i < setting_categories[setting_category_selected]->settings_num; i++)
00091         {
00092             setting = setting_categories[setting_category_selected]->settings[i];
00093 
00094             /* Internal, no need to go any further. */
00095             if (setting->internal)
00096             {
00097                 break;
00098             }
00099 
00100             list_add(list, list->rows, 0, "");
00101         }
00102     }
00103     /* Keybindings? */
00104     else if (setting_type == SETTING_TYPE_KEYBINDINGS)
00105     {
00106         char buf[MAX_BUF];
00107 
00108         for (i = 0; i < keybindings_num; i++)
00109         {
00110             list_add(list, i, 0, keybindings[i]->command);
00111             list_add(list, i, 1, keybind_get_key_shortcut(keybindings[i]->key, keybindings[i]->mod, buf, sizeof(buf)));
00112             list_add(list, i, 2, keybindings[i]->repeat ? "on" : "off");
00113         }
00114     }
00115 
00116     list_offsets_ensure(list);
00117 }
00118 
00124 static void list_handle_mouse_row(list_struct *list, uint32 row, SDL_Event *event)
00125 {
00126     if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT)
00127     {
00128         list_row_clicked = row;
00129         list_clicked = 1;
00130     }
00131     else if (event->type == SDL_MOUSEMOTION)
00132     {
00133         list->row_selected = row + 1;
00134     }
00135 }
00136 
00142 static void list_handle_esc(list_struct *list)
00143 {
00144     (void) list;
00145     popup_destroy_visible();
00146 }
00147 
00153 static void setting_change_value(int cat, int set, sint64 val)
00154 {
00155     setting_struct *setting = setting_categories[cat]->settings[set];
00156 
00157     if (setting->type == OPT_TYPE_BOOL)
00158     {
00159         setting_set_int(cat, set, !setting_get_int(cat, set));
00160     }
00161     else if (setting->type == OPT_TYPE_SELECT || setting->type == OPT_TYPE_RANGE)
00162     {
00163         sint64 old_val, new_val, advance;
00164 
00165         if (!val)
00166         {
00167             return;
00168         }
00169 
00170         new_val = old_val = setting_get_int(cat, set);
00171         advance = 1;
00172 
00173         if (setting->type == OPT_TYPE_RANGE)
00174         {
00175             advance = SETTING_RANGE(setting)->advance;
00176         }
00177 
00178         new_val = old_val + (advance * val);
00179 
00180         if (setting->type == OPT_TYPE_SELECT)
00181         {
00182             setting_select *s_select = SETTING_SELECT(setting);
00183 
00184             if (new_val >= (sint64) s_select->options_len)
00185             {
00186                 new_val = 0;
00187             }
00188             else if (new_val < 0)
00189             {
00190                 new_val = s_select->options_len - 1;
00191             }
00192         }
00193         else if (setting->type == OPT_TYPE_RANGE)
00194         {
00195             setting_range *range = SETTING_RANGE(setting);
00196 
00197             new_val = MAX(range->min, MIN(range->max, new_val));
00198         }
00199 
00200         if (old_val != new_val)
00201         {
00202             setting_set_int(cat, set, new_val);
00203         }
00204     }
00205 }
00206 
00212 static void list_post_column(list_struct *list, uint32 row, uint32 col)
00213 {
00214     int x, y;
00215 
00216     (void) col;
00217 
00218     x = list->x + list->frame_offset;
00219     y = LIST_ROWS_START(list) + (row * LIST_ROW_HEIGHT(list)) + list->frame_offset;
00220 
00221     /* Settings list. */
00222     if (setting_type == SETTING_TYPE_SETTINGS)
00223     {
00224         setting_struct *setting;
00225         int mx, my, mstate;
00226 
00227         setting = setting_categories[setting_category_selected]->settings[row];
00228 
00229         if (setting->internal)
00230         {
00231             return;
00232         }
00233 
00234         /* Show the actual setting name. */
00235         string_blt_shadow_format(list->surface, FONT_ARIAL11, x + 4, y + 5, list->row_selected == row + 1 ? COLOR_HGOLD : COLOR_WHITE, COLOR_BLACK, 0, NULL, "%s:", setting->name);
00236 
00237         mstate = SDL_GetMouseState(&mx, &my);
00238 
00239         /* Checkbox? */
00240         if (setting->type == OPT_TYPE_BOOL)
00241         {
00242             SDL_Rect checkbox;
00243 
00244             checkbox.x = x + list->width - 17;
00245             checkbox.y = y + 1;
00246             checkbox.w = 14;
00247             checkbox.h = 14;
00248             SDL_FillRect(list->surface, &checkbox, SDL_MapRGB(list->surface->format, 0, 0, 0));
00249 
00250             if (setting_get_int(setting_category_selected, row))
00251             {
00252                 lineRGBA(list->surface, checkbox.x, checkbox.y, checkbox.x + checkbox.w, checkbox.y + checkbox.h, 212, 213, 83, 255);
00253                 lineRGBA(list->surface, checkbox.x + checkbox.w, checkbox.y, checkbox.x, checkbox.y + checkbox.h, 212, 213, 83, 255);
00254             }
00255 
00256             draw_frame(list->surface, checkbox.x, checkbox.y, checkbox.w, checkbox.h);
00257 
00258             if (mx >= checkbox.x && mx <= checkbox.x + checkbox.w && my >= checkbox.y && my <= checkbox.y + checkbox.h)
00259             {
00260                 border_create_color(list->surface, &checkbox, "b09a9a");
00261 
00262                 if (list_clicked && list_row_clicked == row && mstate == SDL_BUTTON_LEFT)
00263                 {
00264                     setting_change_value(setting_category_selected, row, 0);
00265                     list_clicked = 0;
00266                 }
00267             }
00268             else
00269             {
00270                 border_create_color(list->surface, &checkbox, "8c7a7a");
00271             }
00272         }
00273         /* Select or range. */
00274         else if (setting->type == OPT_TYPE_SELECT || setting->type == OPT_TYPE_RANGE)
00275         {
00276             SDL_Rect dst;
00277             sint64 val;
00278 
00279             val = setting_get_int(setting_category_selected, row);
00280 
00281             x += list->width - 1;
00282             y += 1;
00283 
00284             x -= Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w;
00285 
00286             if (button_show(BITMAP_BUTTON_ROUND, -1, BITMAP_BUTTON_ROUND_DOWN, x, y, ">", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00287             {
00288                 setting_change_value(setting_category_selected, row, 1);
00289             }
00290 
00291             dst.x = x - 150;
00292             dst.y = y;
00293             dst.w = 150;
00294             dst.h = LIST_ROW_HEIGHT(list) - 2;
00295 
00296             SDL_FillRect(list->surface, &dst, SDL_MapRGB(list->surface->format, 0, 0, 0));
00297 
00298             if (setting->type == OPT_TYPE_SELECT)
00299             {
00300                 string_blt(list->surface, FONT_ARIAL10, SETTING_SELECT(setting)->options[val], dst.x, dst.y, COLOR_WHITE, TEXT_ALIGN_CENTER, &dst);
00301             }
00302             else if (setting->type == OPT_TYPE_RANGE)
00303             {
00304                 string_blt_format(list->surface, FONT_ARIAL10, dst.x, dst.y, COLOR_WHITE, TEXT_ALIGN_CENTER, &dst, "%"FMT64, val);
00305             }
00306 
00307             dst.x -= Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w + 1;
00308 
00309             if (button_show(BITMAP_BUTTON_ROUND, -1, BITMAP_BUTTON_ROUND_DOWN, dst.x, y, "<", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00310             {
00311                 setting_change_value(setting_category_selected, row, -1);
00312             }
00313         }
00314     }
00315 }
00316 
00320 static void setting_keybind_apply(list_struct *list)
00321 {
00322     /* Nothing to apply. */
00323     if (text_input_string[0] == '\0' || setting_keybind_key == SDLK_UNKNOWN)
00324     {
00325         return;
00326     }
00327 
00328     /* Add new. */
00329     if (setting_keybind_id == -1)
00330     {
00331         keybind_add(setting_keybind_key, setting_keybind_mod, text_input_string);
00332         /* It'll be added to the end, so select it. */
00333         list->row_selected = list->rows + 1;
00334         list->row_offset = MIN(list->rows + 1 - list->max_rows, list->row_selected - 1);
00335     }
00336     /* Edit existing. */
00337     else
00338     {
00339         keybind_edit(setting_keybind_id, setting_keybind_key, setting_keybind_mod, text_input_string);
00340     }
00341 
00342     text_input_string_flag = 0;
00343     settings_list_reload(list);
00344 }
00345 
00351 static int setting_keybind_action(SDLKey key, list_struct *list)
00352 {
00353     /* Create a new keybinding. */
00354     if (key == SDLK_n)
00355     {
00356         text_input_open(255);
00357         setting_keybind_step = KEYBIND_STEP_COMMAND;
00358         setting_keybind_key = SDLK_UNKNOWN;
00359         setting_keybind_mod = KMOD_NONE;
00360         setting_keybind_id = -1;
00361         return 1;
00362     }
00363     /* Delete existing keybinding. */
00364     else if (key == SDLK_DELETE)
00365     {
00366         keybind_remove(list->row_selected - 1);
00367         settings_list_reload(list);
00368         return 1;
00369     }
00370     /* Toggle repeat on/off. */
00371     else if (key == SDLK_r)
00372     {
00373         keybind_repeat_toggle(list->row_selected - 1);
00374         settings_list_reload(list);
00375         return 1;
00376     }
00377 
00378     return 0;
00379 }
00380 
00385 static void setting_category_change(int advance)
00386 {
00387     size_t new_cat = setting_category_selected;
00388 
00389     if (advance == 1)
00390     {
00391         if (new_cat == setting_categories_num - 1)
00392         {
00393             new_cat = 0;
00394         }
00395         else
00396         {
00397             new_cat++;
00398         }
00399     }
00400     else if (advance == -1)
00401     {
00402         if (new_cat == 0)
00403         {
00404             new_cat = setting_categories_num - 1;
00405         }
00406         else
00407         {
00408             new_cat--;
00409         }
00410     }
00411 
00412     if (new_cat != setting_category_selected)
00413     {
00414         setting_category_selected = new_cat;
00415         settings_list_reload(list_exists(LIST_SETTINGS));
00416     }
00417 }
00418 
00422 static void settings_popup_draw_func_post(popup_struct *popup)
00423 {
00424     list_struct *list = list_exists(LIST_SETTINGS);
00425     int x, y, mx, my, mstate;
00426 
00427     mstate = SDL_GetMouseState(&mx, &my);
00428 
00429     if (setting_type == SETTING_TYPE_NONE)
00430     {
00431         if (GameStatus == GAME_STATUS_PLAY)
00432         {
00433             button_password.x = popup->x + 15;
00434             button_password.y = popup->y + 15;
00435             button_render(&button_password, "Password");
00436         }
00437     }
00438     else if (setting_type == SETTING_TYPE_SETTINGS)
00439     {
00440         setting_struct *setting;
00441         SDL_Rect dst;
00442 
00443         x = popup->x + 30;
00444         y = popup->y + 50;
00445 
00446         if (button_show(BITMAP_BUTTON_ROUND, -1, BITMAP_BUTTON_ROUND_DOWN, x, y, "<", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00447         {
00448             setting_category_change(-1);
00449         }
00450 
00451         dst.w = list->width + 8 - Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w;
00452         dst.h = 0;
00453 
00454         if (button_show(BITMAP_BUTTON_ROUND, -1, BITMAP_BUTTON_ROUND_DOWN, x + dst.w, y, ">", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00455         {
00456             setting_category_change(1);
00457         }
00458 
00459         setting = setting_categories[setting_category_selected]->settings[list->row_selected - 1];
00460 
00461         dst.w -= Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w;
00462         string_blt(list->surface, FONT_SERIF14, setting_categories[setting_category_selected]->name, x + Bitmaps[BITMAP_BUTTON_ROUND]->bitmap->w, y - 3, COLOR_HGOLD, TEXT_ALIGN_CENTER, &dst);
00463 
00464         dst.h = 66;
00465         string_blt_shadow(list->surface, FONT_ARIAL11, setting->desc ? setting->desc : "", x - 2, popup->y + popup->surface->h - 75, COLOR_WHITE, COLOR_BLACK, TEXT_WORD_WRAP | TEXT_MARKUP, &dst);
00466 
00467         list_show(list, x, y);
00468 
00469         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, popup->x + popup->surface->w - 10 - Bitmaps[BITMAP_BUTTON]->bitmap->w, popup->y + popup->surface->h - 55, "Apply", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00470         {
00471             settings_apply_change();
00472         }
00473 
00474         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, popup->x + popup->surface->w - 10 - Bitmaps[BITMAP_BUTTON]->bitmap->w, popup->y + popup->surface->h - 30, "Done", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00475         {
00476             popup_destroy_visible();
00477         }
00478     }
00479     else if (setting_type == SETTING_TYPE_KEYBINDINGS)
00480     {
00481         SDL_Rect dst;
00482         char key_buf[MAX_BUF];
00483 
00484         x = popup->x + 30;
00485         y = popup->y + 50;
00486         list_show(list, x, y);
00487 
00488         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, popup->x + 30, popup->y + popup->surface->h - 74, "Add", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00489         {
00490             setting_keybind_action(SDLK_n, list);
00491         }
00492 
00493         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, popup->x + 30, popup->y + popup->surface->h - 51, "Remove", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00494         {
00495             setting_keybind_action(SDLK_DELETE, list);
00496         }
00497 
00498         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, popup->x + 30, popup->y + popup->surface->h - 28, "Repeat", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00499         {
00500             setting_keybind_action(SDLK_r, list);
00501         }
00502 
00503         if (text_input_string_flag)
00504         {
00505             string_blt_shadow(ScreenSurface, FONT_ARIAL11, "Command: ", popup->x + 100, popup->y + popup->surface->h - 70, COLOR_WHITE, COLOR_BLACK, 0, NULL);
00506             string_blt_shadow(ScreenSurface, FONT_ARIAL11, "Key: ", popup->x + 100, popup->y + popup->surface->h - 47, COLOR_WHITE, COLOR_BLACK, 0, NULL);
00507             string_blt_shadow(ScreenSurface, FONT_ARIAL10, "Press ESC to cancel.", popup->x + 160, popup->y + popup->surface->h - 34, COLOR_WHITE, COLOR_BLACK, 0, NULL);
00508 
00509             dst.x = popup->x + 160;
00510             dst.y = popup->y + popup->surface->h - 74;
00511             dst.w = Bitmaps[BITMAP_LOGIN_INP]->bitmap->w;
00512             dst.h = Bitmaps[BITMAP_LOGIN_INP]->bitmap->h;
00513 
00514             if (mstate == SDL_BUTTON_LEFT && mx >= dst.x && mx < dst.x + dst.w && my >= dst.y && my < dst.y + dst.h)
00515             {
00516                 setting_keybind_step = KEYBIND_STEP_COMMAND;
00517             }
00518 
00519             if (setting_keybind_step == KEYBIND_STEP_COMMAND)
00520             {
00521                 text_input_show(ScreenSurface, dst.x, dst.y, FONT_ARIAL11, text_input_string, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00522             }
00523             else
00524             {
00525                 text_input_draw_background(ScreenSurface, dst.x, dst.y, BITMAP_LOGIN_INP);
00526                 text_input_draw_text(ScreenSurface, dst.x, dst.y, FONT_ARIAL11, text_input_string, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00527             }
00528 
00529             dst.y += 20;
00530 
00531             if (mstate == SDL_BUTTON_LEFT && mx >= dst.x && mx < dst.x + dst.w && my >= dst.y && my < dst.y + dst.h)
00532             {
00533                 setting_keybind_step = KEYBIND_STEP_KEY;
00534             }
00535 
00536             if (setting_keybind_step == KEYBIND_STEP_COMMAND || setting_keybind_step == KEYBIND_STEP_DONE)
00537             {
00538                 keybind_get_key_shortcut(setting_keybind_key, setting_keybind_mod, key_buf, sizeof(key_buf));
00539             }
00540             else if (setting_keybind_step == KEYBIND_STEP_KEY)
00541             {
00542                 strcpy(key_buf, "Press keyboard shortcut");
00543             }
00544 
00545             text_input_draw_background(ScreenSurface, dst.x, dst.y, BITMAP_LOGIN_INP);
00546             text_input_draw_text(ScreenSurface, dst.x, dst.y, FONT_ARIAL11, key_buf, COLOR_WHITE, TEXT_ALIGN_CENTER, BITMAP_LOGIN_INP, NULL);
00547 
00548             if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, dst.x + dst.w - Bitmaps[BITMAP_BUTTON]->bitmap->w, dst.y + 20, "Apply", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00549             {
00550                 setting_keybind_apply(list);
00551             }
00552         }
00553     }
00554 }
00555 
00559 static void settings_popup_draw_func(popup_struct *popup)
00560 {
00561     SDL_Rect box;
00562 
00563     box.x = 0;
00564     box.y = 10;
00565     box.w = popup->surface->w;
00566     box.h = 0;
00567 
00568     string_blt(popup->surface, FONT_SERIF20, "<u>Settings</u>", box.x, box.y, COLOR_HGOLD, TEXT_ALIGN_CENTER | TEXT_MARKUP, &box);
00569 
00570     if (setting_type == SETTING_TYPE_NONE)
00571     {
00572         size_t i;
00573 
00574         box.y += 50;
00575 
00576         for (i = 0; i < BUTTON_NUM; i++)
00577         {
00578             if (GameStatus != GAME_STATUS_PLAY && (i == BUTTON_BACK || i == BUTTON_LOGOUT))
00579             {
00580                 continue;
00581             }
00582 
00583             if (button_selected == i)
00584             {
00585                 string_blt_shadow_format(popup->surface, FONT_SERIF40, box.x, box.y, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER | TEXT_MARKUP, &box, "<c=#9f0408>&gt;</c> %s <c=#9f0408>&lt;</c>", button_names[i]);
00586             }
00587             else
00588             {
00589 
00590                 string_blt_shadow(popup->surface, FONT_SERIF40, button_names[i], box.x, box.y, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00591             }
00592 
00593             box.y += FONT_HEIGHT(FONT_SERIF40);
00594         }
00595     }
00596     else if (setting_type == SETTING_TYPE_PASSWORD)
00597     {
00598         char buf[MAX_BUF];
00599         int i;
00600 
00601         for (i = 0; i < text_input_count; i++)
00602         {
00603             buf[i] = '*';
00604         }
00605 
00606         buf[i] = '\0';
00607 
00608         box.x = popup->surface->w / 2 - Bitmaps[BITMAP_LOGIN_INP]->bitmap->w / 2;
00609         box.y = popup->surface->h / 2 - Bitmaps[BITMAP_LOGIN_INP]->bitmap->h / 2 - 50;
00610 
00611         text_input_show(popup->surface, box.x, box.y, FONT_ARIAL10, buf, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00612 
00613         if (!setting_password_confirmed)
00614         {
00615             string_blt_shadow(popup->surface, FONT_ARIAL11, "Enter your current password:", 0, box.y - 14, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00616             string_blt_shadow(popup->surface, FONT_ARIAL11, "Allows you to change your character's", 0, box.y + 24, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00617             string_blt_shadow(popup->surface, FONT_ARIAL11, "password. Press Esc to cancel.", 0, box.y + 36, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00618         }
00619         else
00620         {
00621             string_blt_shadow(popup->surface, FONT_ARIAL11, "Enter the new password:", 0, box.y - 14, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00622             string_blt_shadow(popup->surface, FONT_ARIAL11, "Make sure to use a strong password.", 0, box.y + 24, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00623             string_blt_shadow(popup->surface, FONT_ARIAL11, "A good password usually consists of a ", 0, box.y + 36, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00624             string_blt_shadow(popup->surface, FONT_ARIAL11, "mix of uppercase and lowercase letters,", 0, box.y + 48, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00625             string_blt_shadow(popup->surface, FONT_ARIAL11, "numbers, symbols, and does not include", 0, box.y + 60, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00626             string_blt_shadow(popup->surface, FONT_ARIAL11, "words found in common dictionaries.", 0, box.y + 72, COLOR_WHITE, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00627         }
00628     }
00629 }
00630 
00635 static int settings_popup_destroy_callback(popup_struct *popup)
00636 {
00637     (void) popup;
00638     settings_apply_change();
00639     list_remove(list_exists(LIST_SETTINGS));
00640 
00641     if (text_input_string_flag)
00642     {
00643         SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
00644         text_input_string_flag = 0;
00645     }
00646 
00647     keybind_save();
00648 
00649     return 1;
00650 }
00651 
00655 static void list_handle_enter(list_struct *list)
00656 {
00657     if (list->text && list->row_selected)
00658     {
00659         if (setting_type == SETTING_TYPE_KEYBINDINGS)
00660         {
00661             setting_keybind_action(SDLK_n, list);
00662 
00663             setting_keybind_id = list->row_selected - 1;
00664             text_input_add_string(keybindings[setting_keybind_id]->command);
00665             setting_keybind_key = keybindings[setting_keybind_id]->key;
00666             setting_keybind_mod = keybindings[setting_keybind_id]->mod;
00667         }
00668         else if (setting_type == SETTING_TYPE_SETTINGS)
00669         {
00670             setting_change_value(setting_category_selected, list->row_selected - 1, 0);
00671             list_clicked = 0;
00672         }
00673     }
00674 }
00675 
00681 static int list_key_event(list_struct *list, SDLKey key)
00682 {
00683     switch (key)
00684     {
00685         case SDLK_RIGHT:
00686             if (SDL_GetModState() & KMOD_SHIFT)
00687             {
00688                 setting_category_change(1);
00689             }
00690             else
00691             {
00692                 setting_change_value(setting_category_selected, list->row_selected - 1, 1);
00693             }
00694 
00695             break;
00696 
00697         case SDLK_LEFT:
00698             if (SDL_GetModState() & KMOD_SHIFT)
00699             {
00700                 setting_category_change(-1);
00701             }
00702             else
00703             {
00704                 setting_change_value(setting_category_selected, list->row_selected - 1, -1);
00705             }
00706 
00707             break;
00708 
00709         default:
00710             return -1;
00711     }
00712 
00713     return 1;
00714 }
00715 
00719 static void settings_button_handle(size_t button)
00720 {
00721     if (button == BUTTON_KEY_SETTINGS || button == BUTTON_SETTINGS)
00722     {
00723         list_struct *list;
00724         uint32 cols, max_rows;
00725 
00726         if (button == BUTTON_SETTINGS)
00727         {
00728             setting_type = SETTING_TYPE_SETTINGS;
00729             cols = 1;
00730             max_rows = 9;
00731         }
00732         else if (button == BUTTON_KEY_SETTINGS)
00733         {
00734             setting_type = SETTING_TYPE_KEYBINDINGS;
00735             cols = 3;
00736             max_rows = 12;
00737         }
00738 
00739         setting_category_selected = 0;
00740 
00741         list = list_create(LIST_SETTINGS, max_rows, cols, 8);
00742         list->handle_esc_func = list_handle_esc;
00743         list->handle_enter_func = list_handle_enter;
00744         list_scrollbar_enable(list);
00745 
00746         if (button == BUTTON_SETTINGS)
00747         {
00748             list_set_column(list, 0, 430, 7, NULL, -1);
00749             list_set_font(list, FONT_SANS14);
00750             list->handle_mouse_row_func = list_handle_mouse_row;
00751             list->key_event_func = list_key_event;
00752             list->row_highlight_func = NULL;
00753             list->row_selected_func = NULL;
00754             list->post_column_func = list_post_column;
00755         }
00756         else if (button == BUTTON_KEY_SETTINGS)
00757         {
00758             list_set_font(list, FONT_ARIAL11);
00759             list_set_column(list, 0, 273, 7, "Command", -1);
00760             list_set_column(list, 1, 93, 7, "Key", 1);
00761             list_set_column(list, 2, 50, 7, "Repeat", 1);
00762             list->header_height = 7;
00763         }
00764 
00765         list_set_focus(list);
00766         settings_list_reload(list);
00767         return;
00768     }
00769     else if (button == BUTTON_LOGOUT)
00770     {
00771         socket_close(&csocket);
00772         GameStatus = GAME_STATUS_INIT;
00773     }
00774 
00775     popup_destroy_visible();
00776 }
00777 
00780 static int settings_popup_event_func(popup_struct *popup, SDL_Event *event)
00781 {
00782     list_struct *list;
00783 
00784     if (setting_type == SETTING_TYPE_NONE)
00785     {
00786         if (GameStatus == GAME_STATUS_PLAY && button_event(&button_password, event))
00787         {
00788             setting_type = SETTING_TYPE_PASSWORD;
00789             setting_password_confirmed = 0;
00790             text_input_open(64);
00791             return 1;
00792         }
00793 
00794         if (event->type == SDL_KEYDOWN)
00795         {
00796             /* Move the selected button up and down. */
00797             if (event->key.keysym.sym == SDLK_UP || event->key.keysym.sym == SDLK_DOWN)
00798             {
00799                 int selected = button_selected, num_buttons;
00800 
00801                 selected += event->key.keysym.sym == SDLK_DOWN ? 1 : -1;
00802                 num_buttons = (GameStatus == GAME_STATUS_PLAY ? BUTTON_NUM : BUTTON_LOGOUT) - 1;
00803 
00804                 if (selected < 0)
00805                 {
00806                     selected = num_buttons;
00807                 }
00808                 else if (selected > num_buttons)
00809                 {
00810                     selected = 0;
00811                 }
00812 
00813                 button_selected = selected;
00814                 return 1;
00815             }
00816             else if (event->key.keysym.sym == SDLK_RETURN || event->key.keysym.sym == SDLK_KP_ENTER)
00817             {
00818                 settings_button_handle(button_selected);
00819                 return 1;
00820             }
00821         }
00822         else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEMOTION)
00823         {
00824             int x, y, width;
00825             size_t i;
00826 
00827             y = popup->y + 60;
00828 
00829             for (i = 0; i < BUTTON_NUM; i++)
00830             {
00831                 if (GameStatus != GAME_STATUS_PLAY && (i == BUTTON_BACK || i == BUTTON_LOGOUT))
00832                 {
00833                     continue;
00834                 }
00835 
00836                 if (event->motion.y >= y && event->motion.y < y + FONT_HEIGHT(FONT_SERIF40))
00837                 {
00838                     width = string_get_width(FONT_SERIF40, button_names[i], 0);
00839                     x = popup->x + popup->surface->w / 2 - width / 2;
00840 
00841                     if (event->motion.x >= x && event->motion.x < x + width)
00842                     {
00843                         if (event->type == SDL_MOUSEMOTION)
00844                         {
00845                             button_selected = i;
00846                         }
00847                         else if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT)
00848                         {
00849                             settings_button_handle(i);
00850                         }
00851 
00852                         break;
00853                     }
00854                 }
00855 
00856                 y += FONT_HEIGHT(FONT_SERIF40);
00857             }
00858         }
00859     }
00860     else if (setting_type == SETTING_TYPE_PASSWORD)
00861     {
00862         if (event->type == SDL_KEYDOWN)
00863         {
00864             if (event->key.keysym.sym == SDLK_RETURN || event->key.keysym.sym == SDLK_KP_ENTER || event->key.keysym.sym == SDLK_TAB)
00865             {
00866                 if (!setting_password_confirmed)
00867                 {
00868                     if (!strcmp(text_input_string, cpl.password))
00869                     {
00870                         setting_password_confirmed = 1;
00871                         text_input_open(64);
00872                         return 1;
00873                     }
00874                     else
00875                     {
00876                         draw_info(COLOR_RED, "The current password did not match.");
00877                     }
00878                 }
00879                 else
00880                 {
00881                     if (text_input_string[0] == '\0')
00882                     {
00883                         draw_info(COLOR_WHITE, "Canceled password change.");
00884                     }
00885                     else
00886                     {
00887                         SockList sl;
00888                         unsigned char sockbuf[MAX_BUF];
00889 
00890                         sl.buf = sockbuf;
00891                         sl.len = 0;
00892                         SockList_AddString(&sl, "pc ");
00893                         SockList_AddStringTerminated(&sl, cpl.password);
00894                         SockList_AddStringTerminated(&sl, text_input_string);
00895                         send_socklist(sl);
00896 
00897                         strncpy(cpl.password, text_input_string, sizeof(cpl.password) - 1);
00898                         cpl.password[sizeof(cpl.password) - 1] = '\0';
00899                     }
00900                 }
00901             }
00902             else if (event->key.keysym.sym != SDLK_ESCAPE)
00903             {
00904                 text_input_handle(&event->key);
00905                 return 1;
00906             }
00907 
00908             popup_destroy_visible();
00909         }
00910     }
00911     else if ((list = list_exists(LIST_SETTINGS)))
00912     {
00913         if (setting_type == SETTING_TYPE_KEYBINDINGS && (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP))
00914         {
00915             if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_ESCAPE)
00916             {
00917                 if (text_input_string_flag)
00918                 {
00919                     SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
00920                     text_input_string_flag = 0;
00921                     return 1;
00922                 }
00923             }
00924             else if (setting_keybind_step == KEYBIND_STEP_KEY)
00925             {
00926                 if (event->type == SDL_KEYUP)
00927                 {
00928                     setting_keybind_key = event->key.keysym.sym;
00929                     setting_keybind_mod = event->key.keysym.mod;
00930                     setting_keybind_step = KEYBIND_STEP_DONE;
00931                 }
00932 
00933                 return 1;
00934             }
00935             else if (event->key.keysym.sym == SDLK_KP_ENTER || event->key.keysym.sym == SDLK_RETURN || event->key.keysym.sym == SDLK_TAB)
00936             {
00937                 if (setting_keybind_step == KEYBIND_STEP_COMMAND && event->type == SDL_KEYUP)
00938                 {
00939                     setting_keybind_step = KEYBIND_STEP_KEY;
00940                 }
00941                 else if (setting_keybind_step == KEYBIND_STEP_DONE && event->type == SDL_KEYDOWN)
00942                 {
00943                     setting_keybind_apply(list);
00944                 }
00945 
00946                 return 1;
00947             }
00948             else if (text_input_string_flag && event->type == SDL_KEYDOWN)
00949             {
00950                 if (setting_keybind_step == KEYBIND_STEP_COMMAND && text_input_handle(&event->key))
00951                 {
00952                     return 1;
00953                 }
00954             }
00955             else if (event->type == SDL_KEYDOWN && setting_keybind_action(event->key.keysym.sym, list))
00956             {
00957                 return 1;
00958             }
00959         }
00960 
00961         /* Handle list events. */
00962         if (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP)
00963         {
00964             if (list_handle_keyboard(list, &event->key))
00965             {
00966                 return 1;
00967             }
00968         }
00969         else
00970         {
00971             if (list_handle_mouse(list, event->motion.x, event->motion.y, event))
00972             {
00973                 return 1;
00974             }
00975         }
00976     }
00977 
00978     return -1;
00979 }
00980 
00983 void settings_open()
00984 {
00985     popup_struct *popup;
00986 
00987     /* Create the popup. */
00988     popup = popup_create(BITMAP_POPUP);
00989     popup->draw_func = settings_popup_draw_func;
00990     popup->event_func = settings_popup_event_func;
00991     popup->destroy_callback_func = settings_popup_destroy_callback;
00992     popup->draw_func_post = settings_popup_draw_func_post;
00993     setting_type = SETTING_TYPE_NONE;
00994 
00995     button_create(&button_password);
00996 
00997     button_selected = GameStatus == GAME_STATUS_PLAY ? BUTTON_BACK : BUTTON_SETTINGS;
00998 }