/* options - global options that may be set on the command line
   Copyright (C) 1997 Paul Sheer

   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.
 */


#include <config.h>
#include "edit.h"
#include "cmdlineopt.h"
#include "editoptions.h"
#include "mad.h"

extern Window main_window;

extern int option_save_setup_on_exit;
extern int option_suppress_load_files;
extern int option_toolbar;
extern int option_toolhint_milliseconds;

extern int option_text_fg_normal;
extern int option_text_fg_bold;
extern int option_text_fg_italic;

extern int option_text_bg_normal;
extern int option_text_bg_marked;
extern int option_text_bg_highlighted;
extern int option_hint_messages;
extern int option_cursor_blink_rate;
extern int option_pull_down_window_list;
extern int option_find_bracket;
extern int option_edit_right_extreme;
extern int option_edit_left_extreme;
extern int option_edit_top_extreme;
extern int option_edit_bottom_extreme;

extern int option_xor_cursor;
extern int option_flashing_cursor;
extern int option_long_whitespace;

extern int option_force_own_colormap;
extern int option_force_default_colormap;
extern int option_mouse_double_click;
extern int option_middle_button_pastes;
extern int option_syntax_highlighting;
extern int option_auto_spellcheck;

extern int option_new_window_ask_for_file;

#ifdef HAVE_DND
extern int option_dnd_version;
#endif

extern int option_interpret_numlock;

extern char *editor_options_file;
extern char *option_preferred_visual;

static struct {
    char *name;
    int *value;
    char *prompt;
#define TYPE_ON_OFF	1
#define TYPE_VALUE	2
    int type;
} integer_options [] = {
/* The following are check box labels */
	{"option_international_characters", &option_international_characters, gettext_noop(" Display characters outside locale "), TYPE_ON_OFF},
	{"option_word_wrap_line_length", &option_word_wrap_line_length, gettext_noop(" Word wrap line length: "), TYPE_VALUE},
	{"option_tab_spacing", &option_tab_spacing, gettext_noop(" Tab spacing: "), TYPE_VALUE},
	{"option_fill_tabs_with_spaces", &option_fill_tabs_with_spaces, gettext_noop(" Fill tabs with spaces "), TYPE_ON_OFF},
	{"option_return_does_auto_indent", &option_return_does_auto_indent, gettext_noop(" Return does auto indent "), TYPE_ON_OFF},
	{"option_backspace_through_tabs", &option_backspace_through_tabs, gettext_noop(" Backspace through all tabs "), TYPE_ON_OFF},
	{"option_fake_half_tabs", &option_fake_half_tabs, gettext_noop(" Emulate half tabs with spaces "), TYPE_ON_OFF},
	{"option_save_setup_on_exit", &option_save_setup_on_exit, gettext_noop(" Save setup on exit "), TYPE_ON_OFF},
	{"option_suppress_load_files", &option_suppress_load_files, gettext_noop(" Don't load back desktop on startup "), TYPE_ON_OFF},
	{"option_save_mode", &option_save_mode, 0, 0},
	{"option_hint_messages", &option_hint_messages, gettext_noop(" Hint time on title bar "), TYPE_VALUE},
	{"option_cursor_blink_rate", &option_cursor_blink_rate, 0, 0},
	{"option_flashing_cursor", &option_flashing_cursor, gettext_noop(" Flashing cursor "), TYPE_ON_OFF},
	{"option_xor_cursor", &option_xor_cursor, gettext_noop(" Xor cursor "), TYPE_ON_OFF},
	{"option_pull_down_window_list", &option_pull_down_window_list, gettext_noop(" Pull down 'Window' menu "), TYPE_ON_OFF},
	{"option_find_bracket", &option_find_bracket, gettext_noop(" Highlight matching bracket "), TYPE_ON_OFF},
	{"option_edit_right_extreme", &option_edit_right_extreme, 0, 0},
	{"option_edit_left_extreme", &option_edit_left_extreme, 0, 0},
	{"option_edit_top_extreme", &option_edit_top_extreme, 0, 0},
	{"option_edit_bottom_extreme", &option_edit_bottom_extreme, 0, 0},
	{"option_text_line_spacing", &option_text_line_spacing, 0, 0},
	{"option_force_own_colormap", &option_force_own_colormap, 0, 0},
	{"option_force_default_colormap", &option_force_default_colormap, 0, 0},
	{"option_mouse_double_click", &option_mouse_double_click, gettext_noop(" Mouse double click time-out "), TYPE_VALUE},
#ifdef HAVE_DND
	{"option_dnd_version", &option_dnd_version, 0, 0},
#endif
	{"option_max_undo", &option_max_undo, 0, 0},
	{"option_interwidget_spacing", &option_interwidget_spacing, 0, 0},
	{"option_toolbar", &option_toolbar, gettext_noop(" Toolbar on edit windows "), TYPE_ON_OFF},
	{"option_interpret_numlock", &option_interpret_numlock, gettext_noop(" Interpret Num-Lock "), TYPE_ON_OFF},
	{"option_long_whitespace", &option_long_whitespace, gettext_noop(" Whitespace is doubled "), TYPE_ON_OFF},
	{"option_toolhint_milliseconds", &option_toolhint_milliseconds, gettext_noop(" Time to show button hints "), TYPE_VALUE},
	{"option_edit_right_extreme", &option_edit_right_extreme, gettext_noop(" Right cursor limit "), TYPE_VALUE},
	{"option_edit_left_extreme", &option_edit_left_extreme, gettext_noop(" Left cursor limit "), TYPE_VALUE},
	{"option_edit_top_extreme", &option_edit_top_extreme, gettext_noop(" Top cursor limit "), TYPE_VALUE},
	{"option_edit_bottom_extreme", &option_edit_bottom_extreme, gettext_noop(" Bottom cursor limit "), TYPE_VALUE},
#if 0
	{"option_low_bandwidth", &option_low_bandwidth, gettext_noop(" Slow server network connection "), TYPE_ON_OFF},
#endif
	{"option_middle_button_pastes", &option_middle_button_pastes, gettext_noop(" Mouse middle button pastes "), TYPE_ON_OFF},
	{"option_new_window_ask_for_file", &option_new_window_ask_for_file, gettext_noop(" New windows ask for file "), TYPE_ON_OFF},
	{"option_syntax_highlighting", &option_syntax_highlighting, 0, 0},
	{"option_auto_spellcheck", &option_auto_spellcheck, 0, 0},
	{0, 0}
};

extern char *option_display;
extern char *option_geometry;
extern char *option_background_color;
extern char *option_foreground_red;
extern char *option_foreground_green;
extern char *option_foreground_blue;
extern char *option_font;

extern char *option_man_cmdline;
extern char *option_alternate_dictionary;

static struct {
    char *name;
    char **value;
} string_options [] = {
	{"option_whole_chars_search", &option_whole_chars_search},
	{"option_chars_move_whole_word", &option_chars_move_whole_word},
	{"option_display", &option_display},
	{"option_geometry", &option_geometry},
	{"option_background_color", &option_background_color},
	{"option_foreground_red", &option_foreground_red},
	{"option_foreground_green", &option_foreground_green},
	{"option_foreground_blue", &option_foreground_blue},
	{"option_font", &option_font},
	{"option_backup_ext", &option_backup_ext},
	{"option_man_cmdline", &option_man_cmdline},
	{"option_preferred_visual", &option_preferred_visual}, 
	{"option_alternate_dictionary", &option_alternate_dictionary}, 
	{0, 0}
};

static struct {
    char *name;
    int *value;
    char *cname;
} color_options [] = {
	{"option_editor_fg_normal", &option_editor_fg_normal, 0},
	{"option_editor_fg_bold", &option_editor_fg_bold, 0},
	{"option_editor_fg_italic", &option_editor_fg_italic, 0},
	{"option_editor_bg_normal", &option_editor_bg_normal, 0},
	{"option_editor_bg_abnormal", &option_editor_bg_abnormal, 0},
	{"option_editor_bg_marked", &option_editor_bg_marked, 0},
	{"option_editor_bg_marked_abnormal", &option_editor_bg_marked_abnormal, 0},
	{"option_editor_bg_highlighted", &option_editor_bg_highlighted, 0},
	{"option_editor_fg_cursor", &option_editor_fg_cursor, 0},
	{"option_text_fg_normal", &option_text_fg_normal, 0},
	{"option_text_fg_bold", &option_text_fg_bold, 0},
	{"option_text_fg_italic", &option_text_fg_italic, 0},
	{"option_text_bg_normal", &option_text_bg_normal, 0},
	{"option_text_bg_marked", &option_text_bg_marked, 0},
	{"option_text_bg_highlighted", &option_text_bg_highlighted, 0},
	{0, 0}
};


int save_options_section (const char *file, const char *section, const char *text);

extern int display_dnd_protocol_change_message;

int load_setup (const char *file)
{
    static char *options_section = 0;
    char *p, *q;
    int fin = 0;

    if (options_section) {
	free (options_section);
	options_section = 0;
    }
    if (!file)
	return 0;

    options_section = get_options_section (file, "[Options]");
    if (options_section)
	if (strstr (options_section, "option_dnd_version"))
	    display_dnd_protocol_change_message = 1;
    p = q = options_section;

    if (!options_section)
	return -1;

    for (fin = 0; !fin;) {
	if (*q == '\n' || !*q) {
	    int i;
	    if (!*q)
		fin = 1;
	    *q = 0;
	    for (i = 0; string_options[i].name; i++) {
		int l;
		l = strlen (string_options[i].name);
		l = strnlen (p, l);
		if (p[l] && strchr ("\t =", p[l])) {
		    if (!strncasecmp (p, string_options[i].name, l)) {
			*(string_options[i].value) = p + l + strspn (p + l, " =\t");
			break;
		    }
		}
	    }
	    for (i = 0; integer_options[i].name; i++) {
		int l;
		l = strlen (integer_options[i].name);
		l = strnlen (p, l);
		if (p[l] && strchr ("\t =", p[l])) {
		    if (!strncasecmp (p, integer_options[i].name, l)) {
			*(integer_options[i].value) = atoi (p + l + strspn (p + l, " =\t"));
			break;
		    }
		}
	    }
	    for (i = 0; color_options[i].name; i++) {
		int l;
		l = strlen (color_options[i].name);
		l = strnlen (p, l);
		if (p[l] && strchr ("\t =", p[l])) {
		    if (!strncasecmp (p, color_options[i].name, l)) {
			*(color_options[i].value) = atoi (p + l + strspn (p + l, " =\t"));
			color_options[i].cname = p + l + strspn (p + l, " =\t");
			break;
		    }
		}
	    }
	    p = (++q);
	} else {
	    q++;
	}
    }
    return 0;
}

void get_main_window_geometry (void)
{
    int x, y;
    unsigned int width, height, d;
    Window win, root;
    static char save_geom[80];
    int bitmask;

    XGetGeometry (CDisplay, main_window, &root, &x, &y, &width, &height, &d, &d);
    win = CGetWMWindow (main_window);
    XGetGeometry (CDisplay, win, &root, &x, &y, &d, &d, &d, &d);

    if (option_geometry)
	bitmask = XParseGeometry (option_geometry, (int *) &d, (int *) &d, &d, &d);
    else
	bitmask = WidthValue | HeightValue;

    save_geom[0] = '\0';
    if (bitmask & (WidthValue | HeightValue)) {
	strcat (save_geom, itoa (width));
	strcat (save_geom, "x");
	strcat (save_geom, itoa (height));
    }
    if (bitmask & (XValue | YValue)) {
	if (x >= 0)
	    strcat (save_geom, "+");
	strcat (save_geom, itoa (x));
	if (y >= 0)
	    strcat (save_geom, "+");
	strcat (save_geom, itoa (y));
    }
    option_geometry = save_geom;
}

/* option_geometry is not strdup'ed here so don't free it */
int save_setup (const char *file)
{
    char *p, *s;
    int r, i;

    get_main_window_geometry ();

    p = s = CMalloc (16384);

    for (i = 0; string_options[i].name; i++) {
	if (*string_options[i].value) {
	    sprintf (p, "%s = %s\n%n", string_options[i].name, *string_options[i].value, &r);
	    p += r;
	}
    }
    for (i = 0; integer_options[i].name; i++) {
	sprintf (p, "%s = %d\n%n", integer_options[i].name, *integer_options[i].value, &r);
	p += r;
    }
    for (i = 0; color_options[i].name; i++) {
	if (color_options[i].cname)
	    sprintf (p, "%s = %s\n%n", color_options[i].name, color_options[i].cname, &r);
	else
	    sprintf (p, "%s = %d\n%n", color_options[i].name, *color_options[i].value, &r);
	p += r;
    }
    *p = 0;

    r = save_options_section (file, "[Options]", s);
    free (s);
    return r;
}

void save_options (void)
{
    if (save_setup (editor_options_file) < 0)
	CErrorDialog (main_window, 20, 20, _(" Save Options "), "%s", get_sys_error (
	catstrs (_(" Error trying to save : "), editor_options_file, " ", 0)));
}

static char *short_name (char *a, char *b)
{
    static char r[128];
    strcpy (r, a);
    strcat (r, b);
    r[30] = 0;
    return r;
}

#define WHICH_SWITCHES	1
#define WHICH_GENERAL	2

static void assign_options (int which)
{
    int i = 0;
    static char whole_chars_search[128];
    static char whole_chars_move[128];
    static char alternate_dictionary[MAX_PATH_LEN];

    while (integer_options[i].value) {
	if (integer_options[i].prompt) {
	    if (which == WHICH_SWITCHES) {
		if (integer_options[i].type == TYPE_ON_OFF)
		    *integer_options[i].value = (CIdent (short_name (integer_options[i].name, "")))->keypressed;
	    }
	    if (which == WHICH_GENERAL) {
		if (integer_options[i].type == TYPE_VALUE)
		    *integer_options[i].value = atoi ((CIdent (short_name (integer_options[i].name, "")))->text);
	    }
	}
	i++;
    }
    if (which == WHICH_SWITCHES) {
#ifdef HAVE_DND
	option_dnd_version = (CIdent ("dnd_version"))->keypressed;
#endif
	option_auto_para_formatting = (CIdent ("para_form"))->keypressed;
	option_typewriter_wrap = (CIdent ("typew_wrap"))->keypressed;
	option_auto_spellcheck = (CIdent ("auto_spell"))->keypressed;
	option_syntax_highlighting = (CIdent ("syntax_high"))->keypressed;
    }
    if (which == WHICH_GENERAL) {
	strncpy (alternate_dictionary, (CIdent ("options.a_dict"))->text, MAX_PATH_LEN - 1);
	option_alternate_dictionary = alternate_dictionary;
	alternate_dictionary[MAX_PATH_LEN - 1] = '\0';

	strncpy (whole_chars_search, (CIdent ("options.wc_search"))->text, 127);
	option_whole_chars_search = whole_chars_search;
	whole_chars_search[127] = '\0';

	strncpy (whole_chars_move, (CIdent ("options.wc_move"))->text, 127);
	option_chars_move_whole_word = whole_chars_move;
	whole_chars_move[127] = '\0';
    }
}

void draw_options_dialog (Window parent, int x, int y)
{
    Window win;
    XEvent xev;
    CEvent cev;
    int xh, i;
    CState s;
    CWidget *w, *wdt;

    CBackupState (&s);
    CDisable ("*");

    win = CDrawHeadedDialog ("options", parent, x, y, _(" Options "));
    CGetHintPos (&x, &y);

    i = 0;
    xh = x;
    while (integer_options[i].value) {
	if (integer_options[i].prompt && integer_options[i].type == TYPE_VALUE) {
	    wdt = CDrawText (short_name ("T", integer_options[i].name), win, xh, y, _(integer_options[i].prompt));
	    CGetHintPos (&x, 0);
	    w = CDrawTextInput (short_name (integer_options[i].name, ""), win, x, y, FONT_MEAN_WIDTH * 8 + FONT_PIX_PER_LINE + 4, AUTO_HEIGHT, 8, itoa (*integer_options[i].value));
	    w->position |= POSITION_FILL;
	    w->label = _(integer_options[i].prompt);
	    w->hotkey = find_hotkey (w);
	    w->label = 0;
	    wdt->hotkey = w->hotkey;
	    CGetHintPos (0, &y);
	}
	i++;
    }

    CGetHintPos (0, &y);
    CDrawText ("options.twc_search", win, xh, y, _(" Whole chars search: "));
    CGetHintPos (&x, 0);
    (CDrawTextInput ("options.wc_search", win, x, y, FONT_MEAN_WIDTH * 16, AUTO_HEIGHT, 258, option_whole_chars_search)->position) |= POSITION_FILL;
    CGetHintPos (0, &y);
    CDrawText ("options.twc_move", win, xh, y, _(" Whole chars move: "));
    CGetHintPos (&x, 0);
    (CDrawTextInput ("options.wc_move", win, x, y, FONT_MEAN_WIDTH * 16, AUTO_HEIGHT, 258, option_chars_move_whole_word)->position) |= POSITION_FILL;
    CGetHintPos (0, &y);
    CDrawText ("options.ta_dict", win, xh, y, _(" Ispell alternate dict: "));
    CGetHintPos (&x, 0);
    (CDrawTextInput ("options.a_dict", win, x, y, FONT_MEAN_WIDTH * 16, AUTO_HEIGHT, 258, option_alternate_dictionary)->position) |= POSITION_FILL;

    CGetHintPos (0, &y);
    CDrawPixmapButton ("options.ok", win, xh, y, PIXMAP_BUTTON_TICK);
/* Toolhint */
    CSetToolHint ("options.ok", _("Apply options, Enter"));
    CGetHintPos (&xh, 0);
    CDrawPixmapButton ("options.cancel", win, xh, y, PIXMAP_BUTTON_CROSS);
/* Toolhint */
    CSetToolHint ("options.cancel", _("Abort dialog, Escape"));
    CGetHintPos (&xh, 0);
    CDrawPixmapButton ("options.save", win, xh, y, PIXMAP_BUTTON_SAVE);
/* Toolhint */
    CSetToolHint ("options.save", _("Save options"));
    CSetSizeHintPos ("options");
    CMapDialog ("options");

    CFocus (CIdent ("options.ok"));

    for (;;) {
	CNextEvent (&xev, &cev);
	if (!CIdent("options"))
	    break;
	if (!strcmp (cev.ident, "options.cancel") || cev.command == CK_Cancel)
	    break;
	if (!strcmp (cev.ident, "options.ok") || cev.command == CK_Enter) {
/* keypressed holds the whether switch is on or off */
	    assign_options (WHICH_GENERAL);
	    break;
	}
	if (!strcmp (cev.ident, "options.save")) {
/* keypressed holds the whether switch is on or off */
	    assign_options (WHICH_GENERAL);
            save_options ();
	}
    }
    w = CGetEditMenu ();
    if (w)
	CExpose (w->ident);
    CDestroyWidget ("options");
    CRestoreState (&s);
}

void draw_switches_dialog (Window parent, int x, int y)
{
    Window win;
    XEvent xev;
    CEvent cev;
    int xh, yh;
    int i, n;
    CState s;
    CWidget *w;

    CBackupState (&s);
    CDisable ("*");

    win = CDrawHeadedDialog ("options", parent, x, y, _ (" Options "));
    CGetHintPos (&x, &y);

    n = i = 0;
    while (integer_options[i].value) {
	if (integer_options[i].prompt && integer_options[i].type == TYPE_ON_OFF)
	    n++;
	i++;
    }

    i = 0;
    xh = x;
    yh = y;
    while (integer_options[i].value) {
	if (integer_options[i].prompt && integer_options[i].type == TYPE_ON_OFF) {
	    if (n <= 0) {
		get_hint_limits (&xh, 0);	/* half on the left, half on the right */
		n = 9999;
		yh = y;
	    }
	    CDrawSwitch (short_name (integer_options[i].name, ""), win, xh, yh, *integer_options[i].value, _ (integer_options[i].prompt), 0);
	    CGetHintPos (0, &yh);
	    n -= 2;
	}
	i++;
    }

#ifdef HAVE_DND
    get_hint_limits (0, &y);
    CDrawSwitch ("dnd_version_not", win, x, y, !option_dnd_version, _ (" Dnd version 0 "), 1 | RADIO_INVERT_GROUP);
    CDrawSwitch ("dnd_version", win, xh, y, option_dnd_version, _ (" Dnd version 1 "), 1 | RADIO_INVERT_GROUP);
#endif

    get_hint_limits (0, &y);
    CDrawSwitch ("para_form", win, x, y, option_auto_para_formatting, _ (" Auto paragraph formatting "), 2);
    CDrawSwitch ("typew_wrap", win, xh, y, option_typewriter_wrap, _ (" Type-writer wrap "), 2);
    CGetHintPos (0, &y);

    get_hint_limits (0, &y);
    CDrawSwitch ("syntax_high", win, x, y, option_syntax_highlighting, _ (" Syntax highlighting "), 0);
    CDrawSwitch ("auto_spell", win, xh, y, option_auto_spellcheck, _ (" Spellcheck as you type "), 0);
    CGetHintPos (0, &y);

    CDrawPixmapButton ("options.ok", win, x, y, PIXMAP_BUTTON_TICK);
/* Toolhint */
    CSetToolHint ("options.ok", _ ("Apply options, Enter"));
    CGetHintPos (&xh, 0);
    CDrawPixmapButton ("options.cancel", win, xh, y, PIXMAP_BUTTON_CROSS);
/* Toolhint */
    CSetToolHint ("options.cancel", _ ("Abort dialog, Escape"));
    CGetHintPos (&xh, 0);
    CDrawPixmapButton ("options.save", win, xh, y, PIXMAP_BUTTON_SAVE);
/* Toolhint */
    CSetToolHint ("options.save", _ ("Save options"));
    CSetSizeHintPos ("options");
    CMapDialog ("options");

    CFocus (CIdent ("options.ok"));

    for (;;) {
	CNextEvent (&xev, &cev);
	if (!CIdent ("options"))
	    break;
	if (!strcmp (cev.ident, "syntax_high")) {
/* turn off spell checkig if syntax high is on */
	    if ((CIdent ("auto_spell"))->keypressed && !(CIdent ("syntax_high"))->keypressed) {
		(CIdent ("auto_spell"))->keypressed = 0;
		render_switch (CIdent ("auto_spell"));
	    }
	}
	if (!strcmp (cev.ident, "auto_spell")) {
/* turn on syntax highlighting if spellchecking is on */
	    if ((CIdent ("auto_spell"))->keypressed && !(CIdent ("syntax_high"))->keypressed) {
		(CIdent ("syntax_high"))->keypressed = 1;
		render_switch (CIdent ("syntax_high"));
	    }
	}
	if (!strcmp (cev.ident, "options.cancel") || cev.command == CK_Cancel)
	    break;
	if (!strcmp (cev.ident, "options.ok") || cev.command == CK_Enter) {
/* keypressed holds the whether switch is on or off */
	    assign_options (WHICH_SWITCHES);
	    break;
	}
	if (!strcmp (cev.ident, "options.save")) {
/* keypressed holds the whether switch is on or off */
	    assign_options (WHICH_SWITCHES);
	    save_options ();
	}
    }
    w = CGetEditMenu ();
    if (w)
	CExpose (w->ident);
    CDestroyWidget ("options");
    CRestoreState (&s);
}


void save_mode_options_dialog (Window parent, int x, int y)
{
    Window win;
    XEvent xev;
    CEvent cev;
    int x2, y2;
    CState s;
    CWidget *quick, *safe, *backup;

    CBackupState (&s);
    CDisable ("*");

    win = CDrawHeadedDialog ("saving", parent, x, y, _(" Options "));
    CGetHintPos (&x, &y);

    quick = CDrawSwitch ("saving.Rquick", win, x, y, option_save_mode == 0, _(" Quick save "), 1 | RADIO_ONE_ALWAYS_ON);
/* Toolhint */
    CSetToolHint ("saving.Rquick", _("Truncates file then writes contents of editor"));
    CSetToolHint ("saving.Rquick.label", _("Truncates file then writes contents of editor"));
    CGetHintPos (0, &y2);

    safe = CDrawSwitch ("saving.Rsafe", win, x, y2, option_save_mode == 1, _(" Safe save "), 1 | RADIO_ONE_ALWAYS_ON);
/* Toolhint */
    CSetToolHint ("saving.Rsafe", _("Writes to temporary file, then renames if succesful"));
    CSetToolHint ("saving.Rsafe.label", _("Writes to temporary file, then renames if succesful"));
    CGetHintPos (0, &y);

    backup = CDrawSwitch ("saving.Rbackup", win, x, y, option_save_mode == 2, _(" Create backups "), 1 | RADIO_ONE_ALWAYS_ON);
/* Toolhint */
    CSetToolHint ("saving.Rbackup", _("Creates a backup file first"));
    CSetToolHint ("saving.Rbackup.label", _("Creates a backup file first"));
    CGetHintPos (0, &y2);

    CDrawText ("saving.ext", win, x, y2, _(" Backup file extension: "));
    CGetHintPos (&x2, 0);
    CDrawTextInput ("saving.extti", win, x2, y2, FONT_MEAN_WIDTH * 16, AUTO_HEIGHT, 16, option_backup_ext);

    CGetHintPos (0, &y);
    CDrawPixmapButton ("saving.ok", win, x, y, PIXMAP_BUTTON_TICK);
    CGetHintPos (&x2, 0);
    CDrawPixmapButton ("saving.cancel", win, x2, y, PIXMAP_BUTTON_CROSS);
    CGetHintPos (&x2, 0);
    CDrawPixmapButton ("saving.save", win, x2, y, PIXMAP_BUTTON_SAVE);
    CSetSizeHintPos ("saving");
    CMapDialog ("saving");

    CFocus (CIdent ("saving.ok"));

    for (;;) {
	CNextEvent (&xev, &cev);
	if (!CIdent("saving"))
	    break;
	if (!strcmp (cev.ident, "saving.cancel") || cev.command == CK_Cancel)
	    break;
	if (!strcmp (cev.ident, "saving.ok") || cev.command == CK_Enter
	    || !strcmp (cev.ident, "saving.save")) {
/* keypressed holds the whether switch is on or off */
	    if (CIdent ("saving.extti"))
		option_backup_ext = (char *) strdup ((CIdent ("saving.extti"))->text);
	    if (quick->keypressed)
		option_save_mode = 0;
	    else if (safe->keypressed)
		option_save_mode = 1;
	    else if (backup->keypressed)
		option_save_mode = 2;
	    if (!strcmp (cev.ident, "saving.save")) {
		save_options ();
	    } else
		break;
	}
    }
    CDestroyWidget ("saving");
    CRestoreState (&s);
}


static char *syntax_get_line (void *data, int line)
{
    char **names;
    names = (char **) data;
    return names[line];
}

void menu_syntax_highlighting_dialog (Window parent, int x, int y)
{
    char *names[1024] =
    {"None", 0};
    int i, n;
    CWidget *w;

    w = CGetEditMenu ();
    if (!w)
	return;
    if (!w->editor)
	return;

    edit_load_syntax (0, names + 1, 0);
    for (n = 0; names[n]; n++);

    i = CListboxDialog (parent, x, y, 50, 20,
			_ (" Syntax Highlighting "), 0, 0, n,
			syntax_get_line, (void *) names);

    if (i >= 0) {
	if (!i) {
	    edit_free_syntax_rules (w->editor);
	} else {
	    edit_load_syntax (w->editor, 0, names[i]);
	}
	w->editor->explicit_syntax = 1;
    }
    for (n = 1; names[n]; n++)
	free (names[n]);
    CExpose (w->ident);
}



