/* * XPilot NG, a multiplayer space war game. * * Copyright (C) 1991-2001 by * * Bjørn Stabell * Ken Ronny Schouten * Bert Gijsbers * Dick Balaska * * Copyright (C) 2003-2004 Kristian Söderblom * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Configure.c: real-time option control. */ #include "xpclient_x11.h" static int Config_creator(xp_option_t *opt, int widget_desc, int *height); static int Config_create_save(int widget_desc, int *height); static int Config_close(int widget_desc, void *data, const char **strptr); static int Config_next(int widget_desc, void *data, const char **strptr); static int Config_prev(int widget_desc, void *data, const char **strptr); static int Config_save(int widget_desc, void *data, const char **strptr); static int Config_save_confirm_callback(int widget_desc, void *popup_desc, const char **strptr); static int num_default_options = 0; static int max_default_options = 0; static int *default_option_indices = NULL; static int num_color_options = 0; static int max_color_options = 0; static int *color_option_indices = NULL; static bool config_created = false, config_mapped = false; static int config_page, config_x, config_y, config_width, config_height, config_space, config_max, config_button_space, config_text_space, config_text_height, config_button_height, config_entry_height, config_bool_width, config_bool_height, config_int_width, config_double_width, config_arrow_width, config_arrow_height; static int *config_widget_desc, config_save_confirm_desc = NO_WIDGET; static int *config_widget_ids = NULL; static int config_what = CONFIG_NONE; /* this must be updated if new config menu items are added */ static int Nelem_config_creator(void) { if (config_what == CONFIG_DEFAULT) return num_default_options + 1; if (config_what == CONFIG_COLORS) return num_color_options + 1; return 0; } static xp_option_t *Config_creator_option(int i) { int ind = -1; if (config_what == CONFIG_DEFAULT && i >= 0 && i < num_default_options) ind = default_option_indices[i]; if (config_what == CONFIG_COLORS && i >= 0 && i < num_color_options) ind = color_option_indices[i]; return Option_by_index(ind); } static int Update_bool_option(int widget_desc, void *data, bool *val) { xp_option_t *opt = data; UNUSED_PARAM(widget_desc); Set_bool_option(opt, *val, xp_option_origin_config); return 0; } static int Update_int_option(int widget_desc, void *data, int *val) { xp_option_t *opt = data; UNUSED_PARAM(widget_desc); Set_int_option(opt, *val, xp_option_origin_config); return 0; } static int Update_double_option(int widget_desc, void *data, double *val) { xp_option_t *opt = data; UNUSED_PARAM(widget_desc); Set_double_option(opt, *val, xp_option_origin_config); return 0; } static void Create_config(void) { int i, num, height, offset, width, widget_desc; bool full; /* * Window dimensions relative to the top window. */ config_x = 0; config_y = RadarHeight + ButtonHeight + 2; config_width = 256; config_height = top_height - config_y; /* * Space between label-text and label-border. */ config_text_space = 3; /* * Height of a label window. */ config_text_height = 2 * 1 + textFont->ascent + textFont->descent; /* * Space between button-text and button-border. */ config_button_space = 3; /* * Height of a button window. */ config_button_height = buttonFont->ascent + buttonFont->descent + 2 * 1; config_entry_height = MAX(config_text_height, config_button_height); /* * Space between entries and between an entry and the border. */ config_space = 6; /* * Sizes of the different widget types. */ config_bool_width = XTextWidth(buttonFont, "Yes", 3) + 2 * config_button_space; config_bool_height = config_button_height; config_arrow_height = config_text_height; config_arrow_width = config_text_height; config_int_width = 4 + XTextWidth(buttonFont, "10000", 5); config_double_width = 4 + XTextWidth(buttonFont, "0.222", 5); config_max = Nelem_config_creator(); config_widget_desc = malloc(config_max * sizeof(int)); if (config_widget_desc == NULL) { error("No memory for config"); return; } num = -1; full = true; for (i = 0; i < Nelem_config_creator(); i++) { xp_option_t *opt = Config_creator_option(i); if (full) { full = false; num++; config_widget_desc[num] = Widget_create_form(NO_WIDGET, topWindow, config_x, config_y, config_width, config_height, 0); if (config_widget_desc[num] == 0) break; height = config_height - config_space - config_button_height; width = 2 * config_button_space + XTextWidth(buttonFont, "PREV", 4); offset = (config_width - width) / 2; widget_desc = Widget_create_activate(config_widget_desc[num], offset, height, width, config_button_height, 0, "PREV", Config_prev, (void *)(long)num); if (widget_desc == 0) break; width = 2 * config_button_space + XTextWidth(buttonFont, "NEXT", 4); offset = config_width - width - config_space; widget_desc = Widget_create_activate(config_widget_desc[num], offset, height, width, config_button_height, 0, "NEXT", Config_next, (void *)(long)num); if (widget_desc == 0) break; width = 2 * config_button_space + XTextWidth(buttonFont, "CLOSE", 5); offset = config_space; widget_desc = Widget_create_activate(config_widget_desc[num], offset, height, width, config_button_height, 0, "CLOSE", Config_close, (void *)(long)num); if (widget_desc == 0) break; height = config_space; } if (opt == NULL && i != Nelem_config_creator()-1) assert(0); if ((config_widget_ids[i] = Config_creator(opt, config_widget_desc[num], &height)) == 0) { i--; full = true; if (height == config_space) break; continue; } } if (i < Nelem_config_creator()) { for (; num >= 0; num--) { if (config_widget_desc[num] != 0) Widget_destroy(config_widget_desc[num]); } config_created = false; config_mapped = false; } else { config_max = num + 1; config_widget_desc = realloc(config_widget_desc, config_max * sizeof(int)); config_page = 0; for (i = 0; i < config_max; i++) Widget_map_sub(config_widget_desc[i]); config_created = true; config_mapped = false; } } static int Config_close(int widget_desc, void *data, const char **strptr) { UNUSED_PARAM(widget_desc); UNUSED_PARAM(data); UNUSED_PARAM(strptr); Widget_unmap(config_widget_desc[config_page]); config_mapped = false; return 0; } static int Config_next(int widget_desc, void *data, const char **strptr) { int prev_page = config_page; UNUSED_PARAM(widget_desc); UNUSED_PARAM(data); UNUSED_PARAM(strptr); if (config_max > 1) { config_page = (config_page + 1) % config_max; Widget_raise(config_widget_desc[config_page]); Widget_unmap(config_widget_desc[prev_page]); config_mapped = true; } return 0; } static int Config_prev(int widget_desc, void *data, const char **strptr) { int prev_page = config_page; UNUSED_PARAM(widget_desc); UNUSED_PARAM(data); UNUSED_PARAM(strptr); if (config_max > 1) { config_page = (config_page - 1 + config_max) % config_max; Widget_raise(config_widget_desc[config_page]); Widget_unmap(config_widget_desc[prev_page]); config_mapped = true; } return 0; } static int Config_create_bool(int widget_desc, int *height, const char *str, bool val, int (*callback)(int, void *, bool *), void *data) { int offset, label_width, boolw; if (*height + 2*config_entry_height + 2*config_space >= config_height) return 0; label_width = XTextWidth(textFont, str, (int)strlen(str)) + 2 * config_text_space; offset = config_width - (config_space + config_bool_width); if (config_space + label_width > offset) { if (*height + 3*config_entry_height + 2*config_space >= config_height) return 0; } Widget_create_label(widget_desc, config_space, *height + (config_entry_height - config_text_height) / 2, label_width, config_text_height, true, 0, str); if (config_space + label_width > offset) *height += config_entry_height; boolw = Widget_create_bool(widget_desc, offset, *height + (config_entry_height - config_bool_height) / 2, config_bool_width, config_bool_height, 0, val, callback, data); *height += config_entry_height + config_space; return boolw; } static int Config_create_int(int widget_desc, int *height, const char *str, int *val, int min, int max, int (*callback)(int, void *, int *), void *data) { int offset, label_width, intw; if (*height + 2*config_entry_height + 2*config_space >= config_height) return 0; label_width = XTextWidth(textFont, str, (int)strlen(str)) + 2 * config_text_space; offset = config_width - (config_space + 2 * config_arrow_width + config_int_width); if (config_space + label_width > offset) { if (*height + 3*config_entry_height + 2*config_space >= config_height) return 0; } Widget_create_label(widget_desc, config_space, *height + (config_entry_height - config_text_height) / 2, label_width, config_text_height, true, 0, str); if (config_space + label_width > offset) *height += config_entry_height; intw = Widget_create_int(widget_desc, offset, *height + (config_entry_height - config_text_height) / 2, config_int_width, config_text_height, 0, val, min, max, callback, data); offset += config_int_width; Widget_create_arrow_left(widget_desc, offset, *height + (config_entry_height - config_arrow_height) / 2, config_arrow_width, config_arrow_height, 0, intw); offset += config_arrow_width; Widget_create_arrow_right(widget_desc, offset, *height + (config_entry_height-config_arrow_height) / 2, config_arrow_width, config_arrow_height, 0, intw); *height += config_entry_height + config_space; return intw; } static int Config_create_color(int widget_desc, int *height, int color, const char *str, int *val, int min, int max, int (*callback)(int, void *, int *), void *data) { int offset, label_width, colw; if (*height + 2*config_entry_height + 2*config_space >= config_height) return 0; label_width = XTextWidth(textFont, str, (int)strlen(str)) + 2 * config_text_space; offset = config_width - (config_space + 2 * config_arrow_width + config_int_width); if (config_space + label_width > offset) { if (*height + 3*config_entry_height + 2*config_space >= config_height) return 0; } Widget_create_label(widget_desc, config_space, *height + (config_entry_height - config_text_height) / 2, label_width, config_text_height, true, 0, str); if (config_space + label_width > offset) *height += config_entry_height; colw = Widget_create_color(widget_desc, color, offset, *height + (config_entry_height - config_text_height)/2, config_int_width, config_text_height, 0, val, min, max, callback, data); offset += config_int_width; Widget_create_arrow_left(widget_desc, offset, *height + (config_entry_height - config_arrow_height)/2, config_arrow_width, config_arrow_height, 0, colw); offset += config_arrow_width; Widget_create_arrow_right(widget_desc, offset, *height + (config_entry_height - config_arrow_height)/2, config_arrow_width, config_arrow_height, 0, colw); *height += config_entry_height + config_space; return colw; } static int Config_create_double(int widget_desc, int *height, const char *str, double *val, double min, double max, int (*callback)(int, void *, double *), void *data) { int offset, label_width, doublew; if (*height + 2*config_entry_height + 2*config_space >= config_height) return 0; label_width = XTextWidth(textFont, str, (int)strlen(str)) + 2 * config_text_space; offset = config_width - (config_space + 2 * config_arrow_width + config_double_width); if (config_space + label_width > offset) { if (*height + 3*config_entry_height + 2*config_space >= config_height) return 0; } Widget_create_label(widget_desc, config_space, *height + (config_entry_height - config_text_height) / 2, label_width, config_text_height, true, 0, str); if (config_space + label_width > offset) *height += config_entry_height; doublew = Widget_create_double(widget_desc, offset, *height + (config_entry_height - config_text_height) / 2, config_double_width, config_text_height, 0, val, min, max, callback, data); offset += config_double_width; Widget_create_arrow_left(widget_desc, offset, *height + (config_entry_height - config_arrow_height) / 2, config_arrow_width, config_arrow_height, 0, doublew); offset += config_arrow_width; Widget_create_arrow_right(widget_desc, offset, *height + (config_entry_height-config_arrow_height) / 2, config_arrow_width, config_arrow_height, 0, doublew); *height += config_entry_height + config_space; return doublew; } static int Config_create_save(int widget_desc, int *height) { static char save_str[] = "Save Configuration"; int space, button_desc, width = 2 * config_button_space + XTextWidth(buttonFont, save_str, (int)strlen(save_str)); space = config_height - (*height + 2*config_entry_height + 2*config_space); if (space < 0) return 0; button_desc = Widget_create_activate(widget_desc, (config_width - width) / 2, *height + space / 2, width, config_button_height, 0, save_str, Config_save, (void *)save_str); if (button_desc == NO_WIDGET) return 0; *height += config_entry_height + config_space + space; return 1; } static int Config_creator(xp_option_t *opt, int widget_desc, int *height) { if (opt == NULL) return Config_create_save(widget_desc, height); if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_COLORS) { assert (Option_get_type(opt) == xp_int_option); return Config_create_color(widget_desc, height, *opt->int_ptr, Option_get_name(opt), opt->int_ptr, opt->int_minval, opt->int_maxval, Update_int_option, opt); } if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_DEFAULT) { switch (Option_get_type(opt)) { case xp_bool_option: return Config_create_bool(widget_desc, height, Option_get_name(opt), *opt->bool_ptr, Update_bool_option, opt); case xp_int_option: return Config_create_int(widget_desc, height, Option_get_name(opt), opt->int_ptr, opt->int_minval, opt->int_maxval, Update_int_option, opt); case xp_double_option: return Config_create_double(widget_desc, height, Option_get_name(opt), opt->dbl_ptr, opt->dbl_minval, opt->dbl_maxval, Update_double_option, opt); default: return 0; } } return 0; } static void Config_save_failed(const char *reason, const char **strptr) { if (config_save_confirm_desc != NO_WIDGET) Widget_destroy(config_save_confirm_desc); config_save_confirm_desc = Widget_create_confirm(reason, Config_save_confirm_callback); if (config_save_confirm_desc != NO_WIDGET) Widget_raise(config_save_confirm_desc); *strptr = "Saving failed..."; } static int Config_save(int widget_desc, void *button_str, const char **strptr) { int retval; char path[PATH_MAX + 1]; *strptr = "Saving..."; Widget_draw(widget_desc); XFlush(dpy); Xpilotrc_get_filename(path, sizeof(path)); retval = Xpilotrc_write(path); if (retval == -1) { Config_save_failed("Can't find .xpilotrc file", strptr); return 1; } if (retval == -2) { Config_save_failed("Can't open file to save to.", strptr); return 1; } if (config_save_confirm_desc != NO_WIDGET) { Widget_destroy(config_save_confirm_desc); config_save_confirm_desc = NO_WIDGET; } *strptr = (char *) button_str; return 1; } static int Config_save_confirm_callback(int widget_desc, void *popup_desc, const char **strptr) { UNUSED_PARAM(widget_desc); UNUSED_PARAM(strptr); if (config_save_confirm_desc != NO_WIDGET) { Widget_destroy((int)(long int)popup_desc); config_save_confirm_desc = NO_WIDGET; } return 0; } int Config(bool doit, int what) { /* get rid of the old widgets, it's the most easy way */ Config_destroy(); if (doit == false) return false; config_what = what; Create_config(); if (config_created == false) return false; Widget_raise(config_widget_desc[config_page]); config_mapped = true; return true; } void Config_destroy(void) { int i; if (config_created) { if (config_mapped) { Widget_unmap(config_widget_desc[config_page]); config_mapped = false; } for (i = 0; i < config_max; i++) Widget_destroy(config_widget_desc[i]); config_created = false; free(config_widget_desc); config_widget_desc = NULL; config_max = 0; config_page = 0; } } void Config_resize(void) { bool mapped = config_mapped; if (config_created) { Config_destroy(); if (mapped) Config(mapped, config_what); } } void Config_redraw(void) { int i; if (!config_mapped) return; for (i = 0; i < Nelem_config_creator(); i++) Widget_draw(config_widget_ids[i]); } void Config_init(void) { int i, max_ids; for (i = 0; i < num_options; i++) { xp_option_t *opt = Option_by_index(i); if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_COLORS) { STORE(int, color_option_indices, num_color_options, max_color_options, i); } else if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_DEFAULT) { STORE(int, default_option_indices, num_default_options, max_default_options, i); } } /* +1 is for the save widget */ max_ids = MAX(num_color_options, num_default_options) + 1; config_widget_ids = malloc(max_ids * sizeof(int)); if (config_widget_ids == NULL) { error("Config_init: not enough memory."); exit(1); } }