/*
 * Maketool - GTK-based front end for gmake
 * Copyright (c) 1999-2003 Greg Banks
 * 
 * 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 "ui.h"
#include "util.h"

CVSID("$Id: ui.c,v 1.41 2003/10/22 12:13:21 gnb Exp $");

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

void
ui_widget_set_visible(GtkWidget *w, gboolean b)
{
    if (b)
    	gtk_widget_show(w);
    else
    	gtk_widget_hide(w);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

int
ui_combo_get_current(GtkWidget *combo)
{
    GtkList *listw = GTK_LIST(GTK_COMBO(combo)->list);
    
    if (listw->selection == 0)
    	return 0;
    return gtk_list_child_position(listw, (GtkWidget*)listw->selection->data);
}

void
ui_combo_set_current(GtkWidget *combo, int n)
{
    gtk_list_select_item(GTK_LIST(GTK_COMBO(combo)->list), n);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

void
ui_clist_get_strings(GtkWidget *w, int row, int ncols, char *text[])
{
    int i;
    
    for (i=0 ; i<ncols ; i++)
	gtk_clist_get_text(GTK_CLIST(w), row, i, &text[i]);
}

void
ui_clist_set_strings(GtkWidget *w, int row, int ncols, char *text[])
{
    int i;
    
    for (i=0 ; i<ncols ; i++)
	gtk_clist_set_text(GTK_CLIST(w), row, i, text[i]);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static GPtrArray *ui_groups = 0;

static void
ui_group_destroy_cb(GtkWidget *w, gpointer user_data)
{
    gint group = GPOINTER_TO_INT(user_data);
    
    g_ptr_array_index(ui_groups, group) = 
    	g_list_remove(g_ptr_array_index(ui_groups, group), w);
}

void
ui_group_add(guint group, GtkWidget *w)
{
    if (ui_groups == 0)
    	ui_groups = g_ptr_array_new();
	
    if (group >= ui_groups->len)
	g_ptr_array_set_size(ui_groups, group+1);
	
    g_ptr_array_index(ui_groups, group) = 
    	g_list_prepend(g_ptr_array_index(ui_groups, group), w);
	
    gtk_signal_connect(GTK_OBJECT(w), "destroy",
    	    GTK_SIGNAL_FUNC(ui_group_destroy_cb), GINT_TO_POINTER(group));
}

void
ui_group_set_sensitive(guint group, gboolean b)
{
    GList *list;
    
    if (ui_groups == 0 || group >= ui_groups->len)
    	return;
    list = g_ptr_array_index(ui_groups, group);
    
    for ( ; list != 0 ; list = list->next)
    	gtk_widget_set_sensitive(GTK_WIDGET(list->data), b);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

#define FILESEL_CALLBACK_DATA "ui_callback"

static void
ui_file_sel_ok_cb(GtkWidget *w, gpointer data)
{
    GtkWidget *filesel = GTK_WIDGET(data);
    void (*callback)(const char *filename);
    
    callback = (void (*)(const char*))gtk_object_get_data(
    	    	    	    GTK_OBJECT(filesel), FILESEL_CALLBACK_DATA);
    gtk_widget_hide(filesel);
    (*callback)(gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)));
}

GtkWidget *
ui_create_file_sel(
    GtkWidget *parent,
    const char *title,
    void (*callback)(const char *filename),
    const char *filename)
{
    GtkWidget *filesel;
    
    filesel = gtk_file_selection_new(title);
    gtk_window_set_position(GTK_WINDOW(filesel), GTK_WIN_POS_CENTER);
    gtk_window_set_transient_for(GTK_WINDOW(filesel),
    	    GTK_WINDOW(parent));
    gtk_signal_connect(
	    GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button),
            "clicked", GTK_SIGNAL_FUNC(ui_file_sel_ok_cb),
	    (gpointer)filesel);
    gtk_signal_connect_object(
	    GTK_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
            "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide),
	    GTK_OBJECT(filesel));
    gtk_object_set_data(GTK_OBJECT(filesel), FILESEL_CALLBACK_DATA,
    	(gpointer)callback);
    if (filename != 0)
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename);

    return filesel;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

#define UI_MENU_ACCEL_GROUP	"ui_menu_accel_group"

static GtkAccelGroup *ui_accel_group = 0;

void
ui_set_accel_group(GtkAccelGroup *ag)
{
    ui_accel_group = ag;
}

#if !GTK2

static GtkWidget *
_ui_create_label(
    GtkWidget *item,
    const char *label,
    guint *uline_key_p)
{
    GtkWidget *label_w;
    
    label_w = gtk_accel_label_new(label);
    if (uline_key_p != 0)
	 *uline_key_p = gtk_label_parse_uline(GTK_LABEL(label_w), label);
    gtk_misc_set_alignment(GTK_MISC(label_w), 0.0, 0.5);
    gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(label_w), item);
    gtk_container_add(GTK_CONTAINER(item), label_w);
    gtk_widget_show(label_w);
    return label_w;
}    

#endif /* !GTK2 */

static GtkWidget *
_ui_add_menu_aux(
    GtkWidget *parent,	    /* menubar or menu */
    const char *label,
    gboolean douline,
    gboolean is_right,
    gint position)
{
    GtkWidget *menu, *item;
#if !GTK2
    guint uline_key = 0;
#endif
    
#if GTK2
    if (douline)
	item = gtk_menu_item_new_with_mnemonic(label);
    else
	item = gtk_menu_item_new_with_label(label);
#else /* !GTK2 */
    item = gtk_menu_item_new();
    _ui_create_label(item, label, (douline ? &uline_key : 0));
#endif /* !GTK2 */
    gtk_widget_show(item);
    
#if !GTK2
    if (douline && uline_key != 0)
	gtk_widget_add_accelerator(item, "activate", 
				ui_accel_group, uline_key, GDK_MOD1_MASK, 0);
#endif /* !GTK2 */

    menu = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);

    if (GTK_IS_MENU_BAR(parent))
    {
    	if (position < 0)
	    gtk_menu_bar_append(GTK_MENU_BAR(parent), item);
	else
	    gtk_menu_bar_insert(GTK_MENU_BAR(parent), item, position);
    }
    else
    {
    	if (position < 0)
	    gtk_menu_append(GTK_MENU(parent), item);
	else
	    gtk_menu_insert(GTK_MENU(parent), item, position);
    }
    
    if (is_right)
    	gtk_menu_item_right_justify(GTK_MENU_ITEM(item));

    return menu;
}

GtkWidget *
ui_add_menu(GtkWidget *menubar, const char *label)
{
    return _ui_add_menu_aux(menubar, label, TRUE, FALSE, -1);
}

GtkWidget *
ui_add_menu_right(GtkWidget *menubar, const char *label)
{
    return _ui_add_menu_aux(menubar, label, TRUE, TRUE, -1);
}

GtkWidget *
ui_add_submenu(GtkWidget *menu, gboolean douline, const char *label)
{
    return _ui_add_menu_aux(menu, label, douline, FALSE, -1);
}

#if !GTK2

static void
_ui_add_menu_accel(
    GtkWidget *menu,
    GtkWidget *item,
    guint uline_key)
{
    GtkAccelGroup *menu_accel_grp;
    GtkWidget *menu_shell;
 
    if (uline_key == 0)
    	return;

    menu_accel_grp = gtk_object_get_data(GTK_OBJECT(menu),
			    UI_MENU_ACCEL_GROUP);
    if (menu_accel_grp == 0)
    {
	menu_shell = gtk_widget_get_ancestor(menu, gtk_menu_shell_get_type());
	menu_accel_grp = gtk_accel_group_new();
	gtk_accel_group_attach(menu_accel_grp, GTK_OBJECT(menu_shell));
	gtk_object_set_data(GTK_OBJECT(menu), UI_MENU_ACCEL_GROUP,
	    	   	     menu_accel_grp);
    }
    gtk_widget_add_accelerator(item, "activate", 
			    menu_accel_grp, uline_key, 0, 0);
}
#endif /* !GTK2 */


static void
_ui_add_accel(
    GtkWidget *menu,
    GtkWidget *item,
    const char *accel)
{
    GdkModifierType mods = 0;
    guint key = 0;

    if (ui_accel_group == 0)
    	return;

    gtk_accelerator_parse(accel, &key, &mods);
    gtk_widget_add_accelerator(item, "activate", 
			    ui_accel_group, key, mods, GTK_ACCEL_VISIBLE);
#if 0
    gtk_accel_group_add(ui_accel_group,
	    key, mods, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(item), "activate");
#endif
}


GtkWidget *
ui_add_button_2(
    GtkWidget *menu,
    const char *label,
    gboolean douline,
    const char *accel,
    void (*callback)(GtkWidget*, gpointer),
    gpointer calldata,
    gint group,
    gint position)
{
    GtkWidget *item;
#if !GTK2
    guint uline_key = 0;
#endif

#if GTK2
    if (douline)
	item = gtk_menu_item_new_with_mnemonic(label);
    else
	item = gtk_menu_item_new_with_label(label);
#else
    item = gtk_menu_item_new();
    _ui_create_label(item, label, (douline ? &uline_key : 0));
#endif

    if (position < 0)
	gtk_menu_append(GTK_MENU(menu), item);
    else
	gtk_menu_insert(GTK_MENU(menu), item, position);
    if (callback != 0)
	gtk_signal_connect(GTK_OBJECT(item), "activate", 
    	    GTK_SIGNAL_FUNC(callback), calldata);
    if (group >= 0)
    	ui_group_add(group, item);
	
#if !GTK2
    /* Handle underline accelerator */
    if (douline)
	_ui_add_menu_accel(menu, item, uline_key);
#endif

    /* Handle accelerator */
    if (accel != 0)
	_ui_add_accel(menu, item, accel);

    gtk_widget_show(item);
    return item;
}

GtkWidget *
ui_add_button(
    GtkWidget *menu,
    const char *label,
    const char *accel,
    void (*callback)(GtkWidget*, gpointer),
    gpointer calldata,
    gint group)
{
    return ui_add_button_2(menu, label, TRUE, accel, callback, calldata, group, -1);
}


GtkWidget *
ui_add_tearoff(GtkWidget *menu)
{
    GtkWidget *item;

    item = gtk_tearoff_menu_item_new();
    gtk_menu_append(GTK_MENU(menu), item);
    gtk_widget_show(item);
    return item;
}

GtkWidget *
ui_add_toggle(
    GtkWidget *menu,
    const char *label,
    const char *accel,
    void (*callback)(GtkWidget*, gpointer),
    gpointer calldata,
    GtkWidget *radio_other,
    gboolean set)
{
    GtkWidget *item;
#if !GTK2
    guint uline_key;
#endif
    
#if GTK2
    if (radio_other == 0)
    {
	item = gtk_check_menu_item_new_with_mnemonic(label);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), set);
    }
    else
    {
    	GSList *group;
	group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(radio_other));
	item = gtk_radio_menu_item_new_with_mnemonic(group, label);
    }
#else /* !GTK2 */
    if (radio_other == 0)
    {
	item = gtk_check_menu_item_new();
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), set);
    }
    else
    {
    	GSList *group;
	group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(radio_other));
	item = gtk_radio_menu_item_new(group);
    }

    _ui_create_label(item, label, &uline_key);
#endif /* !GTK2 */
    
    gtk_menu_append(GTK_MENU(menu), item);
    gtk_signal_connect(GTK_OBJECT(item), "activate", 
    	GTK_SIGNAL_FUNC(callback), calldata);
    
#if !GTK2
    /* Handle underline accelerator */
    _ui_add_menu_accel(menu, item, uline_key);
#endif /* !GTK2 */

    /* Handle accelerator */
    if (accel != 0)
	_ui_add_accel(menu, item, accel);

    gtk_widget_show(item);    
    return item;
}


GtkWidget *
ui_add_separator(GtkWidget *menu)
{
    GtkWidget *item;

    item = gtk_menu_item_new();
    gtk_menu_append(GTK_MENU(menu), item);
    gtk_widget_show(item);
    return item;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

void
ui_delete_menu_items(GtkWidget *menu)
{
    GList *list, *next;
    
    for (list = gtk_container_children(GTK_CONTAINER(menu)) ;
    	 list != 0 ;
	 list = next)
    {
    	GtkWidget *child = (GtkWidget *)list->data;
	next = list->next;

    	if (GTK_IS_TEAROFF_MENU_ITEM(child))
	    continue;
	    
	gtk_widget_destroy(child);	
    }
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

int
ui_container_num_visible_children(GtkContainer *con)
{
    GList *kids = gtk_container_children(con);
    int nvis = 0;
    
    while (kids != 0)
    {
    	if (GTK_WIDGET_VISIBLE(kids->data))
	    nvis++;
    	kids = g_list_remove_link(kids, kids);
    }
    
    return nvis;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

GtkWidget *
ui_tool_create(
    GtkWidget *toolbar,
    const char *name,
    const char *tooltip,
    char **pixmap_xpm,
    ui_callback_t callback,
    gpointer user_data,
    gint group,
    const char *helptag)
{
    GdkPixmap *pm = 0;
    GdkBitmap *mask = 0;
    GtkWidget *item;
    GdkWindow *win = gtk_widget_get_ancestor(toolbar, gtk_window_get_type())->window;


    pm = gdk_pixmap_create_from_xpm_d(win, &mask, 0, pixmap_xpm);
    item = gtk_toolbar_append_item(
    	GTK_TOOLBAR(toolbar),
    	name,
	tooltip,
	0,				/* tooltip_private_text */
    	gtk_pixmap_new(pm, mask),
    	GTK_SIGNAL_FUNC(callback),
	user_data);
    if (group >= 0)
    	ui_group_add(group, item);
    if (helptag != 0)
    	ui_set_help_tag(item, helptag);

    return item;
}

void
ui_tool_add_space(GtkWidget *toolbar)
{
    gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static const char tool_menu_key[] = "ui-tool-menu-key";

static void
ui_tool_drop_enter(GtkWidget *button, gpointer data)
{
    gtk_button_enter(GTK_BUTTON(data));
}

static void
ui_tool_drop_leave(GtkWidget *button, gpointer data)
{
    gtk_button_leave(GTK_BUTTON(data));
}

GtkWidget *
ui_tool_drop_menu_create(
    GtkWidget *toolbar,
    GtkWidget *linked_item, 	/* may be NULL */
    gint group,
    const char *helptag)
{
    GtkWidget *mbar, *mitem, *arrow, *menu;

    mbar = gtk_menu_bar_new();
    mitem = gtk_menu_item_new();
    arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
    gtk_container_add(GTK_CONTAINER(mitem), arrow);
    gtk_widget_show(arrow);
    gtk_menu_bar_append(GTK_MENU_BAR(mbar), mitem);
    gtk_widget_show(mitem);
    gtk_toolbar_append_widget(GTK_TOOLBAR(toolbar), mbar, 0, 0);
    gtk_widget_show(mbar);

    menu = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), menu);
    
    gtk_object_set_data(GTK_OBJECT(mbar), tool_menu_key, menu);
    if (linked_item != 0 && GTK_IS_BUTTON(linked_item))
    {
	gtk_signal_connect(GTK_OBJECT(mitem), "select",
    		GTK_SIGNAL_FUNC(ui_tool_drop_enter), linked_item);
	gtk_signal_connect(GTK_OBJECT(mitem), "deselect",
    		GTK_SIGNAL_FUNC(ui_tool_drop_leave), linked_item);
    }

    if (group >= 0)
    	ui_group_add(group, mbar);
    if (helptag != 0)
    	ui_set_help_tag(mbar, helptag);

    return mbar;
}

GtkWidget *
ui_tool_drop_menu_get_menu(GtkWidget *button)
{
    return gtk_object_get_data(GTK_OBJECT(button), tool_menu_key);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

/* prevents the dialog being inconveniently destroyed rather than hidden */
static void
ui_dialog_delete_cb(GtkWidget *w, void *user_data)
{
    gtk_widget_hide(w);
}


GtkWidget *
ui_create_dialog(
    GtkWidget *parent,
    const char *title)
{
    GtkWidget *dialog, *bbox;
    
    dialog = gtk_dialog_new();
    gtk_window_set_title(GTK_WINDOW(dialog), title);
    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
    gtk_window_set_transient_for(GTK_WINDOW(dialog),
    	    GTK_WINDOW(parent));
    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 4);
    gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", 
    	GTK_SIGNAL_FUNC(ui_dialog_delete_cb), 0);

    bbox = gtk_hbutton_box_new();
    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), bbox);
    gtk_widget_show(bbox);

    return dialog;
}    

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/


GtkWidget *
ui_dialog_create_button(
    GtkWidget *dialog,
    const char *label,
    ui_callback_t callback,
    gpointer user_data)
{
    GtkWidget *button, *bbox;
    
    button = gtk_button_new_with_label(label);
    GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);    
    bbox = ((GtkBoxChild *)GTK_BOX(GTK_DIALOG(dialog)->action_area)->children->data)->widget;
    gtk_box_pack_start(GTK_BOX(bbox), button,
    	    	      /*expand*/FALSE, /*fill*/TRUE, /*padding*/0);
    gtk_signal_connect(GTK_OBJECT(button), "clicked", 
    	    	       GTK_SIGNAL_FUNC(callback), user_data);
    gtk_widget_show(button);

    return button;
}

static void
ui_dialog_ok_cb(GtkWidget *w, gpointer data)
{
    gtk_widget_hide(GTK_WIDGET(data));
}

GtkWidget *
ui_create_ok_dialog(
    GtkWidget *parent,
    const char *title)
{
    GtkWidget *dialog, *btn;
    
    dialog = ui_create_dialog(parent, title);
    
    btn = ui_dialog_create_button(dialog, _("OK"), ui_dialog_ok_cb, (gpointer)dialog);
    ui_set_help_tag(btn, "ok");
    gtk_window_set_default(GTK_WINDOW(dialog), btn);
    return dialog;
}    

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

#define APPLY_DIALOG_DATA "ui_apply_dialog"

typedef struct
{
    GtkWidget *dialog;
    ui_callback_t apply_cb;
    GtkWidget *ok_btn;
    GtkWidget *apply_btn;
    gpointer user_data;
} ApplyDialog;


static void
ui_apply_dialog_apply_cb(GtkWidget *w, gpointer data)
{
    ApplyDialog *ad = (ApplyDialog *)data;

    (*ad->apply_cb)(ad->dialog, ad->user_data);
    gtk_widget_set_sensitive(ad->ok_btn, FALSE);
    gtk_widget_set_sensitive(ad->apply_btn, FALSE);
    gtk_window_set_default(GTK_WINDOW(ad->dialog), ad->apply_btn);
}

static void
ui_apply_dialog_cancel_cb(GtkWidget *w, gpointer data)
{
    ApplyDialog *ad = (ApplyDialog *)data;

    gtk_widget_hide(ad->dialog);
}

static void
ui_apply_dialog_ok_cb(GtkWidget *w, gpointer data)
{
    ui_apply_dialog_apply_cb(w, data);
    ui_apply_dialog_cancel_cb(w, data);
}

GtkWidget *
ui_create_apply_dialog(
    GtkWidget *parent,
    const char *title,
    ui_callback_t apply_cb,
    gpointer data)
{
    ApplyDialog *ad;
    GtkWidget *btn;
    
    ad = g_new(ApplyDialog, 1);
    ad->apply_cb = apply_cb;
    ad->user_data = data;

    ad->dialog = ui_create_dialog(parent, title);

    gtk_object_set_data(GTK_OBJECT(ad->dialog), APPLY_DIALOG_DATA,
    	(gpointer)ad);
    
    ad->ok_btn = ui_dialog_create_button(ad->dialog, _("OK"), ui_apply_dialog_ok_cb, (gpointer)ad);
    gtk_widget_set_sensitive(ad->ok_btn, FALSE);
    ui_set_help_tag(ad->ok_btn, "ok");
    ad->apply_btn = ui_dialog_create_button(ad->dialog, _("Apply"), ui_apply_dialog_apply_cb, (gpointer)ad);
    gtk_widget_set_sensitive(ad->apply_btn, FALSE);
    ui_set_help_tag(ad->apply_btn, "apply");
    btn = ui_dialog_create_button(ad->dialog, _("Cancel"), ui_apply_dialog_cancel_cb, (gpointer)ad);
    ui_set_help_tag(btn, "cancel");
    gtk_window_set_default(GTK_WINDOW(ad->dialog), btn);
    
    return ad->dialog;
}    

void
ui_dialog_changed(GtkWidget *dialog)
{
    ApplyDialog *ad = (ApplyDialog *)gtk_object_get_data(GTK_OBJECT(dialog), APPLY_DIALOG_DATA);

    gtk_widget_set_sensitive(ad->ok_btn, TRUE);
    gtk_widget_set_sensitive(ad->apply_btn, TRUE);
    gtk_window_set_default(GTK_WINDOW(ad->dialog), ad->ok_btn);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "gnome-info.xpm"

static void
ui_message_dialog_hide_cb(GtkWidget *w, gpointer data)
{
    gtk_widget_destroy(GTK_WIDGET(data));
}

GtkWidget *
ui_message_dialog(GtkWidget *parent, const char *title, const char *msg)
{
    GtkWidget *shell;
    GtkWidget *hbox;
    GtkWidget *icon;
    GtkWidget *label;
    static GdkPixmap *pm;
    static GdkBitmap *mask;

    shell = ui_create_ok_dialog(parent, title);
    gtk_signal_connect(GTK_OBJECT(shell), "hide",
    	    	       GTK_SIGNAL_FUNC(ui_message_dialog_hide_cb), shell);

    hbox = gtk_hbox_new(FALSE, 5);
    gtk_container_border_width(GTK_CONTAINER(hbox), 4);
    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(shell)->vbox), hbox);
    gtk_widget_show(hbox);

    if (pm == 0)
    {
	pm = gdk_pixmap_create_from_xpm_d(parent->window,
    		    &mask, 0, gnome_info_xpm);
    }
    icon = gtk_pixmap_new(pm, mask);
    gtk_container_add(GTK_CONTAINER(hbox), icon);
    gtk_widget_show(icon);

    label = gtk_label_new(msg);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
    gtk_container_add(GTK_CONTAINER(hbox), label);
    gtk_widget_show(label);
    
    return shell;
}

GtkWidget *
ui_message_dialog_f(GtkWidget *parent, const char *title, const char *fmt, ...)
{
    va_list args;
    char *msg;
    GtkWidget *w;
    
    va_start(args, fmt);
    msg = g_strdup_vprintf(fmt, args);
    va_end(args);

    w = ui_message_dialog(parent, title, msg);
    
    g_free(msg);

    return w;
}

void
ui_message_wait(GtkWidget *w)
{
    int oldmodal = GTK_WINDOW(w)->modal;

    gtk_widget_ref(w);
    gtk_window_set_modal(GTK_WINDOW(w), TRUE);
    gtk_widget_show(w);
    
    do
    {
    	gtk_main_iteration();
    }
    while (GTK_WIDGET_VISIBLE(w));

    gtk_window_set_modal(GTK_WINDOW(w), oldmodal);
    gtk_widget_unref(w);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static const char _ui_help_key[] = "ui-help-key";

void
ui_set_help_tag(GtkWidget *w, const char *tag)
{
    gtk_object_set_data(GTK_OBJECT(w), _ui_help_key, (void*)tag);
}

const char *
ui_get_help_tag(GtkWidget *w)
{
    while (w != 0)
    {
	const char *tag = (const char *)gtk_object_get_data(GTK_OBJECT(w), _ui_help_key);
	if (tag != 0)
	    return tag;
	w = w->parent;
    }
    return 0;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

static GHashTable *ui_config_data = 0;
static char *ui_config_filename = 0;

static void
ui_config_set_take_value(const char *name, char *value)
{
    gpointer orig_key = 0, orig_value = 0;

    if (g_hash_table_lookup_extended(ui_config_data, name, &orig_key, &orig_value))
    {
	g_hash_table_remove(ui_config_data, orig_key);
    	g_free(orig_key);
	g_free(orig_value);
    }

    if (value != 0)
	g_hash_table_insert(ui_config_data, g_strdup(name), value);
#if DEBUG
    fprintf(stderr, "ui_config_set: %s = \"%s\"\n", name, value);
#endif
}

static void
ui_config_set(const char *name, const char *value)
{
    ui_config_set_take_value(name, g_strdup(value));
}


int
ui_config_init(const char *pkg)
{
    estring name, value, filename;
    FILE *fp;
    int c;
    int nread = 0;

    ui_config_data = g_hash_table_new(g_str_hash, g_str_equal);

    estring_init(&name);
    estring_init(&value);

    estring_init(&filename);
    estring_append_string(&filename, getenv("HOME"));
    estring_append_string(&filename, "/.");
    estring_append_string(&filename, pkg);
    estring_append_string(&filename, "rc");
    ui_config_filename = filename.data;
    
    if ((fp = fopen(ui_config_filename, "r")) == 0)
    {
    	if (errno != ENOENT)
	    perror(ui_config_filename);
	return -1;
    }

    for (;;) 
    {
   	c = fgetc(fp);
	if (c == EOF)
	    break;

   	/* skip comments */
	while (c == '#')
	{
	     while ((c = fgetc(fp)) != '\n')
	     	;
	     c = fgetc(fp);
	}

	/* name */
	estring_truncate(&name);
	estring_append_char(&name, c);
	while ((c = fgetc(fp)) != '=' && c != '\n')
	    estring_append_char(&name, c);
	if (c == '\n')
	    ungetc(c, fp);
	
	/* value */
	estring_truncate(&value);
	/* swallow c == '=' */
	while ((c = fgetc(fp)) != '\n')
	    estring_append_char(&value, c);

	/* got name, value */
	ui_config_set(name.data, value.data);
	nread++;
    }
   
    fclose(fp);
    estring_free(&name);
    estring_free(&value);
    return nread;
}

static UiEnumRec ui_boolean_enum_def[] = {
{"TRUE",	TRUE},
{"FALSE",	FALSE},
{"true",	TRUE},
{"false",	FALSE},
{"yes",		TRUE},
{"no",		FALSE},
{"on",		TRUE},
{"off",		FALSE},
{"1",		TRUE},
{"0",		FALSE},
{0, 0}};

char *
ui_config_get_string(const char *name, const char *defv)
{
    const char *v;
    
    v = (const char *)g_hash_table_lookup(ui_config_data, name);
    if (v == 0)
    	v = defv;
    return g_strdup(v);
}

int
ui_config_get_int(const char *name, int defv)
{
    char *v;
    
    v = (char *)g_hash_table_lookup(ui_config_data, name);
    return (v == 0 ? defv : atoi(v));
}

int
ui_config_get_enum(const char *name, int defv, UiEnumRec *enumdef)
{
    char *v;
    
    v = (char *)g_hash_table_lookup(ui_config_data, name);
    if (v != 0)
    {
	for ( ; enumdef->name != 0 ; enumdef++)
    	    if (!strcmp(enumdef->name, v))
		return enumdef->value;
		
	if (isdigit(v[0]))
	    return atoi(v);
    }
    return defv;
}

int
ui_config_get_flags(const char *name, int defv, UiEnumRec *enumdef)
{
    char *v;
    int val = 0;
    char **p, **parts;
    UiEnumRec *er;
    
    v = (char *)g_hash_table_lookup(ui_config_data, name);
    if (v == 0)
    	return defv;
	
    parts = g_strsplit(v, ",", 1024);
    for (p = parts ; *p ; p++)
    {
	if (isdigit((*p)[0]))
	{
	    val |= atoi(*p);
	    continue;
	}
	
	for (er = enumdef ; er->name != 0 ; er++)
	{
    	    if (!strcmp(er->name, *p))
	    {
	    	val |= er->value;
		break;
	    }
    	}
    }
    g_strfreev(parts);
    return val;
}


gboolean
ui_config_get_boolean(const char *name, gboolean defv)
{
    return (gboolean)ui_config_get_enum(name, (int)defv, ui_boolean_enum_def);
}

void
ui_config_set_string(const char *name, const char *val)
{
    ui_config_set(name, val);
}

void
ui_config_set_int(const char *name, int val)
{
    char buf[256];
    
    sprintf(buf, "%d", val);
    ui_config_set(name, buf);
}

void
ui_config_set_enum(const char *name, int val, UiEnumRec *enumdef)
{
    char *v = 0, buf[256];
    
    for ( ; enumdef->name != 0 ; enumdef++)
    	if (enumdef->value == val)
	{
	    v = enumdef->name;
	    break;
	}
    if (v == 0)
    {
    	sprintf(buf, "%d", val);
	v = buf;
    }
    
    ui_config_set(name, v);
}

void
ui_config_set_flags(const char *name, int val, UiEnumRec *enumdef)
{
    estring stringval;
    
    estring_init(&stringval);
    
    for ( ; val != 0 && enumdef->name != 0 ; enumdef++)
    {
    	if (enumdef->value & val)
	{
	    if (stringval.length > 0)
	    	estring_append_char(&stringval, ',');
	    estring_append_string(&stringval, enumdef->name);
	    val &= ~enumdef->value;
	}
    }
    if (val != 0)
    {
	if (stringval.length > 0)
	    estring_append_char(&stringval, ',');
    	estring_append_printf(&stringval, "%d", val);
    }
    
    ui_config_set_take_value(name, stringval.data);
}


void
ui_config_set_boolean(const char *name, gboolean val)
{
    ui_config_set_enum(name, (val ? TRUE : FALSE), ui_boolean_enum_def);
}


void
ui_config_backup(void)
{
    char *bakfile;
    
    bakfile = g_strconcat(ui_config_filename, ".OLD", 0);
    if (rename(ui_config_filename, bakfile) < 0)
    	perror(bakfile);
    g_free(bakfile);
}

static void
ui_config_save_one(gpointer keyp, gpointer valuep, gpointer user_data)
{
    FILE *fp = (FILE *)user_data;
    const char *key = (const char *)keyp;
    const char *value = (const char *)valuep;
    
    fprintf(fp, "%s=%s\n", key, value);
}

void
ui_config_sync(void)
{
    FILE *fp;
   
    if ((fp = fopen(ui_config_filename, "w")) == 0)
    {
   	 perror(ui_config_filename);
   	 return;
    }
    fputs("# Written by maketool. Do not edit\n", fp);
    g_hash_table_foreach(ui_config_data, ui_config_save_one, (gpointer)fp);
    fclose(fp);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*END*/


syntax highlighted by Code2HTML, v. 0.9.1