/*
 * gui.c
 * 
 * Copyright (C) 2006-2007  Josef Kufner <jk@myserver.cz>
 * 
 * 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.
 *
 */
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

#include "gui.h"
#include "gui_callbacks.h"
#include "glade_interface.h"
#include "glade_support.h"
#include "status.h"
#include "options.h"
#include "playerlist.h"
#include "backend.h"

#define DEBUG 		0
#include "debug.h"

struct s_gui gui = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

GtkWidget *dialog_connect = NULL;
GtkWidget *dialog_about = NULL;
GtkWidget *dialog_game_select = NULL;
GtkWidget *dialog_network_profiles = NULL;
GtkWidget *dialog_option_browser = NULL;


/* from interfaces.c */
#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  g_object_set_data_full (G_OBJECT (component), name, \
    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)


static GtkTreeViewColumn *player_list_column[6];

static struct s_gui_page {
	char *option,		/* option to update */
	     *win_title,	/* detached window title */
	     *win_class,	/* detached window class */
	     *menuitem_label,	/* menu item label :) */

	     *widget_name,	/* name of widget to detach */
	     *hide_name,	/* name of widget to hide */
	     *parent_name,	/* name of original parent widget (NULL = same as hide_name) */
	     *notify_icon_name; /* name of notify icon */
	
	GtkWidget *widget,	/* widget to detach */
		  *hide,	/* widget to hide when detached */
		  *window,	/* detached window */
		  *parent,	/* original parent widget */
		  *menuitem,	/* check menu item to update */
		  *notify_icon;	/* notify icon */
} gui_page[GUI_PAGE_MAX] = {
	/* GUI_PAGE_BOARD */ { 
		"detached_board", NULL, "board", NULL,
		"board_alignment", "board_vbox", NULL, "board_label_image",
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_CHAT */ {
		"detached_chat", NULL, "chat", NULL,
		"chat_vpaned", "chat_vbox", NULL, "chat_label_image",
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_GAMELOG */ {
		"detached_gamelog", NULL, "gamelog", NULL,
		"gamelog_scrolledwindow", "gamelog_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_NETLOG */ {
		"detached_netlog", NULL, "netlog", NULL,
		"netlog_scrolledwindow", "netlog_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	}
};

/*****************************************************************************
 * 	GUI Functions
 ****************************************************************************/

void gui_update_main_window(void) {
	const char *str = NULL;
	int i, pages;
	
	/* menu network */
	gtk_widget_set_sensitive(lookup_widget(main_window, "network_connect"),
			backend_network == NULL);
	gtk_widget_set_sensitive(lookup_widget(main_window, "network_disconnect"),
			backend_network != NULL);

	/* ikonka spojeni */
	gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(main_window, "statusbar_connect")),
			gui.is_online ? "gtk-connect":"gtk-disconnect",
			GTK_ICON_SIZE_MENU);

	/* connection frame */
	if (backend_network) {
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "connection_backend_value_label")),
				option_get_string("main", "net", "backend"));
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "connection_address_value_label")),
				option_get_string("main", "net", "address"));
		gtk_widget_show(lookup_widget(main_window, "connection_table"));
		gtk_widget_hide(lookup_widget(main_window, "connection_connect_button"));
	} else {
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "connection_backend_value_label")), "");
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "connection_address_value_label")), "");
		gtk_widget_hide(lookup_widget(main_window, "connection_table"));
		gtk_widget_show(lookup_widget(main_window, "connection_connect_button"));
	}
	
	/* chat */
	gtk_widget_set_sensitive(lookup_widget(main_window, "chat_label2"),
			gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "chat_entry"),
			gui.is_online);

	/* seznam hracu + nastaveni hry */
	gtk_widget_set_sensitive(lookup_widget(main_window, "players_frame"), gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_frame"), gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_name_button"), gui.can_select_game);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_role_combobox"), gui.can_select_role);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_start_button"), gui.can_start_game);
	//gtk_widget_set_sensitive(lookup_widget(main_window, "game_end_button"), gui.can_end_game);
	
	if ((str = option_get_string("main", "game", "backend"))) {
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "game_name_button_label")), str);
	} else {
		gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "game_name_button_label")), "--");
	}
	

	
	/* menu hra */
	/* lock */
	gtk_widget_set_sensitive(lookup_widget(main_window, "players_lock_togglebutton"),
			0 && gui.is_online && gui.is_game);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(main_window, "players_lock_togglebutton")),
			0 && gui.is_locked);
	//gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_lock_togglebutton")),
	//		0 && gui.is_locked);
	if (gui.is_locked) {
		gtk_widget_show(lookup_widget(main_window, "statusbar_lock_eventbox"));
	} else {
		gtk_widget_hide(lookup_widget(main_window, "statusbar_lock_eventbox"));
	}
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_terminate"), backend_game != NULL);

	/* game menu */
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_select"), gui.can_select_game && gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_start"), gui.can_start_game && gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_surrender"), gui.can_end_game && gui.is_online);

	/* pause */
	gtk_widget_set_sensitive(lookup_widget(main_window, "game_pause"), gui.is_game);
	//gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "game_pause")),
	//		0 && gui.is_paused);
	if (gui.is_paused) {
		gtk_widget_show(lookup_widget(main_window, "statusbar_pause_eventbox"));
	} else {
		gtk_widget_hide(lookup_widget(main_window, "statusbar_pause_eventbox"));
	}

	
	/* menu test */
	gtk_widget_set_sensitive(lookup_widget(main_window, "test_draw"),
			!gui.is_online);
	gtk_widget_set_sensitive(lookup_widget(main_window, "test_clean"),
			!gui.is_online);

	gui_set_semaphore(-1);

	/* player list columns */
	i = 0;
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_ack"));
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_nick"));
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_address"));
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_role"));
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_score"));
	gtk_tree_view_column_set_visible(player_list_column[i++], option_get_integer("main", "ui", "pl_col_connection"));
	
	/* update menu */
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_ack")),
			option_get_integer("main", "ui", "pl_col_ack"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_nick")),
			option_get_integer("main", "ui", "pl_col_nick"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_address")),
			option_get_integer("main", "ui", "pl_col_address"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_role")),
			option_get_integer("main", "ui", "pl_col_role"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_score")),
			option_get_integer("main", "ui", "pl_col_score"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "players_column_connection")),
			option_get_integer("main", "ui", "pl_col_connection"));
	
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "pref_autoswitch")),
			option_get_integer("main", "ui", "autoswitch"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "pref_showlogs")),
			option_get_integer("main", "ui", "show_logs"));
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(main_window, "pref_enable_comm_log")),
			option_get_integer("main", "ui", "enable_comm_log"));


	/* update pages */
	if (option_get_integer("main", "ui", "show_logs")) {
		if (!gui_page[GUI_PAGE_GAMELOG].window)
			gtk_widget_show(lookup_widget(main_window, "gamelog_vbox"));
		if (!gui_page[GUI_PAGE_NETLOG].window)
			gtk_widget_show(lookup_widget(main_window, "netlog_vbox"));
	} else {
		gtk_widget_hide(lookup_widget(main_window, "gamelog_vbox"));
		gtk_widget_hide(lookup_widget(main_window, "netlog_vbox"));
	}
	
	pages = 0;
	for (i = 0; i < GUI_PAGE_MAX; i++) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gui_page[i].menuitem),
				option_get_integer("main", "ui", gui_page[i].option));
		if (GTK_WIDGET_VISIBLE(gui_page[i].parent)) {
			pages++;
		}
	}
	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook")), pages > 1);

	if (pages < 1) {
		gtk_widget_hide(lookup_widget(main_window, "main_notebook"));
		gtk_window_resize(GTK_WINDOW(main_window), 1, 1);
	} else {
		gtk_widget_show(lookup_widget(main_window, "main_notebook"));
		GTK_WIDGET_UNSET_FLAGS (lookup_widget(main_window, "main_notebook"), GTK_CAN_FOCUS);
	}
}

void gui_set_semaphore(int x) {
	if (x != -1)
		gui.semafor = x;
	
	/* semafor */
	gtk_widget_set_sensitive(lookup_widget(main_window, "statusbar_turn_no"), gui.semafor & 1);
	gtk_widget_set_sensitive(lookup_widget(main_window, "statusbar_turn_yes"), gui.semafor & 2);
}

GtkWidget *gui_create_main_window(void)
{
	GtkWidget *wid;
	GtkSizeGroup *size_group;
	GtkWidget *mnu, *mnu_item;
	int i;

	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeView *treeview;

	gchar *widget_names[] = {
		"game_start_button",
		"players_btn_vbox",
		NULL
	};

	DBG_MSG(3, "gui_create_main_window");

	main_window = create_main_window();
	g_assert(main_window != NULL);

	size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

	gui_page[GUI_PAGE_BOARD].win_title    = _("Herní deska - Netboard");
	gui_page[GUI_PAGE_CHAT].win_title    = _("Chat & nastavení hry - Netboard");
	gui_page[GUI_PAGE_GAMELOG].win_title = _("Game Log - Netboard");
	gui_page[GUI_PAGE_NETLOG].win_title  = _("Net Log - Netboard");

	gui_page[GUI_PAGE_BOARD].menuitem_label    = _("_Herní deska");
	gui_page[GUI_PAGE_CHAT].menuitem_label    = _("_Chat & nastavení hry");
	gui_page[GUI_PAGE_GAMELOG].menuitem_label = _("_Game Log");
	gui_page[GUI_PAGE_NETLOG].menuitem_label  = _("_Net Log");

	mnu = gtk_menu_new ();
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget(main_window, "mnu_detach_tab")), mnu);
	gtk_widget_show (mnu);

	for (i = 0; i < GUI_PAGE_MAX; i++) {
		gui_page[i].widget = lookup_widget(main_window, gui_page[i].widget_name);
		gui_page[i].hide = lookup_widget(main_window, gui_page[i].hide_name);
		if (!gui_page[i].parent_name)
			gui_page[i].parent = gui_page[i].hide;
		else
			gui_page[i].parent = lookup_widget(main_window, gui_page[i].parent_name);

		gui_page[i].menuitem = gtk_check_menu_item_new_with_mnemonic (gui_page[i].menuitem_label);
		gtk_container_add (GTK_CONTAINER (mnu), gui_page[i].menuitem);
		gtk_widget_show (gui_page[i].menuitem);
		g_signal_connect ((gpointer)(gui_page[i].menuitem), "activate",
				G_CALLBACK (on_pref_detach_page_activate), (gpointer) ((int)i));

		if (gui_page[i].notify_icon_name)
			gui_page[i].notify_icon = lookup_widget(main_window, gui_page[i].notify_icon_name);
	}

	
	for (i = 0; widget_names[i]; i++) {
		wid = lookup_widget(main_window, widget_names[i]);
		gtk_size_group_add_widget (size_group, wid);
	}
	
	gtk_size_group_set_mode (size_group, GTK_SIZE_GROUP_HORIZONTAL);

	DBG_MSG(5, "after_create_main_window: player list");

	/*** prepare player list ***/
	treeview = GTK_TREE_VIEW(lookup_widget(main_window, "players_treeview"));
	i = 0;

	mnu = gtk_menu_new ();
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget(main_window, "mnu_players_columns")), mnu);
	gtk_widget_show (mnu);
	
	/* column: option ack */
	DBG_MSG(5, "after_create_main_window: player list: nick");
	renderer = gtk_cell_renderer_pixbuf_new ();
	g_object_set(renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
	column = gtk_tree_view_column_new_with_attributes (_("Ack"), renderer, "stock-id", 0, NULL);
	gtk_tree_view_column_set_resizable (column, FALSE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 0);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("_Ack"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_ack");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_ack");

	/* column: option nick */
	DBG_MSG(5, "after_create_main_window: player list: nick");
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Přezdívka"), renderer, "text", 1, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 1);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("_Přezdívka"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_nick");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_nick");

	/* column: option address */
	DBG_MSG(5, "after_create_main_window: player list: address");
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Adresa"), renderer, "text", 2, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 2);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("A_dresa"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_address");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_address");

	/* column: option role */
	DBG_MSG(5, "after_create_main_window: player list: role");
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Role"), renderer, "text", 3, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 3);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("_Role"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_role");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_role");
	
	/* column: option score */
	DBG_MSG(5, "after_create_main_window: player list: score");
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Skóre"), renderer, "text", 4, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 4);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("_Skóre"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_score");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_score");
	
	/* column: option conn_stat */
	DBG_MSG(5, "after_create_main_window: player list: conn_stat");
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Spojení"), renderer, "text", 5, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 5);
	player_list_column[i++] = column;

	mnu_item = gtk_check_menu_item_new_with_mnemonic (_("Sp_ojení"));
	gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
	gtk_widget_show (mnu_item);
	g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), "pl_col_connection");
	GLADE_HOOKUP_OBJECT (main_window, mnu_item, "players_column_connection");

	gui_update_playerlist();

	/* desk */
	gtk_widget_set_double_buffered(lookup_widget(main_window, "board_drawingarea"), TRUE);

	/* force switch page to chat */
	gtk_notebook_set_current_page(GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook")), GUI_PAGE_CHAT);

	return main_window;
}

void gui_enable_board(void) {
	gtk_widget_set_sensitive(lookup_widget(main_window, "board_drawingarea"), TRUE);
}

void gui_disable_board(void) {
	gtk_widget_set_sensitive(lookup_widget(main_window, "board_drawingarea"), FALSE);
}

static void append_text_to (GtkWidget *text_view, char* text) {
	GtkTextIter iter;
	GtkTextBuffer *buf;
	GtkTextMark *mark;

	assert(text_view != NULL);
	assert(text != NULL);
	
	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(text_view));
	
	gtk_text_buffer_get_end_iter (buf, &iter);
	gtk_text_buffer_insert(buf, &iter, text, -1);
	
	/* scroll down */
	gtk_text_buffer_place_cursor(buf, &iter);
	mark = gtk_text_buffer_get_insert(buf);
	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text_view), mark, 0.0, FALSE, 0.0, 1.0);
}

void gui_erase_logs (void) {
	gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW(lookup_widget(main_window, "gamelog_textview"))), "", -1);
	gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW(lookup_widget(main_window, "netlog_textview"))), "", -1);
}

void gui_page_notify(GUI_PAGE page)
{
	static GtkWidget *nb = NULL;
	if (!nb)
		nb = lookup_widget(main_window, "main_notebook");
	
	if (gui_page[page].notify_icon && page != gtk_notebook_get_current_page(GTK_NOTEBOOK(nb)))
		gtk_widget_show(gui_page[page].notify_icon);
}

void gui_append_to_chat(char *fmt, ...) {
	static GtkWidget *tv = NULL, *nb = NULL, *li = NULL;
	va_list ap;
	char *m;
	static int cached_nl = 0;
	int l;

	assert(fmt != NULL);

	if (!tv) tv = lookup_widget(main_window, "chat_textview");
	if (!nb) nb = lookup_widget(main_window, "main_notebook");
	if (!li) li = lookup_widget(main_window, "chat_label_image");

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		l = strlen(m);
		if (cached_nl) {
			append_text_to(tv, "\n");
			cached_nl = 0;
		}
		if (l > 0 && m[l - 1] == '\n') {
			cached_nl = 1;
			m[l - 1] = 0;
		}
		append_text_to(tv, m);
	}
	g_free(m);
	va_end(ap);
	
	/* show alert icon */
	gui_page_notify(GUI_PAGE_CHAT);
}

void gui_append_to_netlog(char *fmt, ...) {
	static GtkWidget *tv = NULL;
	va_list ap;
	char *m;

	assert(fmt != NULL);

	if (!tv) tv = lookup_widget(main_window, "netlog_textview");

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		append_text_to(tv, m);
	}
	g_free(m);
	va_end(ap);
}

void gui_append_to_gamelog(char *fmt, ...) {
	static GtkWidget *tv = NULL;
	va_list ap;
	char *m;

	assert(fmt != NULL);

	if (!tv) tv = lookup_widget(main_window, "gamelog_textview");

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		append_text_to(tv, m);
	}
	g_free(m);
	va_end(ap);
}


void gui_set_statusbar_clock(int is_visible, int set_icon, gchar *fmt,...) {
	va_list ap;
	char *m;
	static GtkWidget *sl;
	static const char *icon_name[GUI_ICON_MAX + 1] = {
		"",
		"statusbar_image_tip",
		"statusbar_image_info",
		"statusbar_image_question",
		"statusbar_image_warning",
		"statusbar_image_error",
		NULL
	};
	static GtkWidget *icon[GUI_ICON_MAX];
	static int active_icon = 0;
	int i;
	
	if (!sl) {
		sl = lookup_widget(main_window, "statusbar_clock_label");
		for (i = 0; i < GUI_ICON_MAX; i++) {
			if (icon_name[i] && icon_name[i][0])
				icon[i] = lookup_widget(main_window, icon_name[i]);
			else
				icon[i] = NULL;
		}
	}
	
	if (set_icon < GUI_ICON_MAX && set_icon >= 0) {
		if (icon[active_icon])
			gtk_widget_hide(icon[active_icon]);
		if (icon[set_icon])
			gtk_widget_show(icon[set_icon]);
		active_icon = set_icon;
	}

	if (is_visible)
		gtk_widget_show(sl);
	else
		gtk_widget_hide(sl);
	
	if (fmt) {
		va_start(ap, (char *) fmt);
		if ((m = g_strdup_vprintf((char *) fmt, ap))) {
			gtk_label_set_text(GTK_LABEL(sl), m);
		}
		va_end(ap);
		g_free(m);
	}
}


void gui_set_statusbar_text(gchar *fmt,...) {
	va_list ap;
	char *m;
	static GtkLabel *sl = NULL;

	DBG_MSG(3, "gui_set_statusbar_text");
	if (!sl) {
		sl = GTK_LABEL(lookup_widget(main_window, "statusbar_label"));
	}

	if (fmt) {
		va_start(ap, (char *) fmt);
		if ((m = g_strdup_vprintf((char *) fmt, ap))) {
			gtk_label_set_text(sl, m);
		}
		va_end(ap);
		g_free(m);
	} else {
		gtk_label_set_text(sl, "");
	}
}

void gui_set_statusbar_progress(int visible, gdouble fraction, gchar *fmt,...) {
	va_list ap;
	char *m;
	static GtkWidget *sp;
	
	if (!sp) sp = lookup_widget(main_window, "statusbar_progressbar");
	
	if (visible)
		gtk_widget_show(sp);
	else
		gtk_widget_hide(sp);

	if (fraction > 1.0)
		fraction = 1.0;
	if (fraction < 0.0)
		fraction = 0.0;
	
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sp), fraction);
	
	if (fmt) {
		va_start(ap, (char *) fmt);
		if ((m = g_strdup_vprintf((char *) fmt, ap))) {
			gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sp), m);
		}
		va_end(ap);
		g_free(m);
	} else {
		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sp), "");
	}
}

void gui_show_dialog_connect(void) {
	GtkComboBox *dir_combo;
	const char *last_backend = option_get_string("main", "net", "profile");
	char *cat = NULL, *mod = NULL, *opt = NULL;
	int opt_iter = 0;
	const char *name = NULL, *address = NULL;
	char *last_mod = "";
	GtkListStore *store = NULL;
	GtkTreeIter store_iter;

	last_backend = last_backend ? last_backend : "";
	
	/* vytvoreni dialogu */
	dialog_connect = create_dialog_connect ();
	dir_combo = GTK_COMBO_BOX(lookup_widget(dialog_connect, "profile_combobox"));
	
	store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_combo_box_set_model(GTK_COMBO_BOX(dir_combo), GTK_TREE_MODEL(store));
	
	/* nasypani dat */
	for (opt_iter = 0; option_list_opt("network", &opt_iter, &cat, &mod, &opt); opt_iter++) {
		if (cat && mod && opt) {
			if (strcmp(last_mod, mod) != 0 && (name = option_get_string(cat, mod, "name"))) {
				DBG_MSG(8, "gui_show_dialog_connect: found \"%s\"", name);
				address = option_get_string("network", mod, "default_address");
				
				gtk_list_store_append (store, &store_iter);
				gtk_list_store_set (store, &store_iter,
						0, name ? name : "",
						1, mod ? mod : "",
						2, address ? address : "",
						-1);
				
				if (strcmp(mod, last_backend) == 0)
					gtk_combo_box_set_active_iter(dir_combo, &store_iter);
			}
			last_mod = mod;
		}
	}
	g_object_unref(store);
	
	gtk_entry_set_text(GTK_ENTRY(lookup_widget(dialog_connect, "address_entry")), option_get_string("main", "net", "address"));
	
	/* zobrazeni dialogu */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_connect), GTK_WINDOW(main_window));
	gtk_widget_show (dialog_connect);
}

void gui_show_dialog_game_select(void) {
	GDir *dir;
	gchar *dir_name;
	GtkTreeStore *store;
	GtkTreeIter iter;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeView *treeview;
	GtkTreeSelection *selection;
	const char *dir_game = option_get_string("main", "dir", "game");
	const char *default_game = option_get_string("main", "game", "backend");

	/* nacteni seznamu dostupnych her */
	if (!(dir = g_dir_open(dir_game, 0, NULL))) {
		gui_show_error_message(main_window, _("Nepovedlo se načíst seznam her"), _("Nelze otevřít \"%s\":\n%s"), dir_game, g_strerror(errno));
		perror("g_dir_open");
		return;
	}
	
	/* vytvoreni dialogu */
	dialog_game_select = create_dialog_game_select();
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_game_select, "game_select_treeview"));
	
	/* priprava modelu*/
	store = gtk_tree_store_new (1, G_TYPE_STRING);

	/* priprava widgetu */
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Hra"), renderer, "text", 0, NULL);
	gtk_tree_view_append_column(treeview, column);
	gtk_tree_view_column_set_sort_column_id(column, 0);
	gtk_tree_view_set_search_column (treeview, 0);
	

	/* nasypani dat */
	while((dir_name = (gchar*) g_dir_read_name(dir))) {
		if (dir_name[0] != '.') {
			DBG_MSG(8, "gui_show_dialog_game_select: found dir \"%s\"", dir_name);
			gtk_tree_store_append (store, &iter, NULL);
			gtk_tree_store_set(store, &iter, 0, dir_name, -1);
			if (default_game && strcmp(default_game, dir_name) == 0) {
				DBG_MSG(4, "gui_show_dialog_game_select: selecting \"%s\"", dir_name);
				gtk_tree_selection_select_iter(selection, &iter);
			}
		}
	}
	g_dir_close(dir);
	g_object_unref(store);

	/* zobrazeni dialogu */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_game_select), GTK_WINDOW(main_window));
	gtk_widget_show (dialog_game_select);
}

void gui_show_error_message(GtkWidget *parent, char *title, char *fmt, ...)
{
	GtkWidget *dialog;
	char *m;
	va_list ap;

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
				GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_OK,
				title);
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), m);
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
		gtk_dialog_run (GTK_DIALOG (dialog));
		gtk_widget_destroy (dialog);
	}
	va_end(ap);
	g_free(m);
}

void gui_switch_main_page(int page) {
	if (option_get_integer("main", "ui", "autoswitch"))
		gtk_notebook_set_current_page(GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook")), page);
}

void gui_wait_for_callback(void) {
	gtk_main_iteration_do(TRUE);
}

void gui_show_option_browser(void) {
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeView *treeview;

	DBG_MSG(3, "gui_show_option_browser");

	dialog_option_browser = create_dialog_option_browser();
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_option_browser, "option_treeview"));

	option_set_update_callback(gui_update_option_browser);
	
	/* column: option name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Kategorie"), renderer, "text", 0, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 0);

	/* column: module name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Modul"), renderer, "text", 1, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 1);

	/* column: option name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Volba"), renderer, "text", 2, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 2);

	/* column: option value */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Hodnota"), renderer, "text", 3, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 3);
	
	/* column: option type */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Typ"), renderer, "text", 4, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 4);
	
	gui_update_option_browser();
	
	/* show window */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_option_browser), GTK_WINDOW(main_window));
	gtk_widget_show(dialog_option_browser);
}

void gui_update_option_browser(void) {
	GtkListStore *store;
	GtkTreeIter iter;
	GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(dialog_option_browser, "option_treeview"));
	char *name, *cat, *mod;
	const char *value;
	const char *type;
	int i;
	GtkAdjustment *vadj;

	if (!dialog_option_browser)
		return;

	DBG_MSG(2, "gui_update_option_browser");

	/* save cursor position */
	vadj = gtk_tree_view_get_vadjustment(treeview);
	
	/* add data to the list store */
	store = gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	for (i = 0; option_list_opt(NULL, &i, &cat, &mod, &name); i++) {
		if (name && name[0]) {
			value = option_get_string_by_id(i);
			type = option_get_type_name_by_id(i);
			DBG_MSG(6, "gui_update_option_browser: adding option [ %s :: %s :: %s ]", cat, mod, name);
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter, 0, cat, 1, mod, 2, name, 3, value, 4, type, -1);
		}
	}
	g_object_unref(store);

	/* restore position */
	if (vadj)
		gtk_tree_view_set_vadjustment(treeview, vadj);

	gtk_tree_view_columns_autosize(treeview);

}


void gui_update_playerlist(void) {
	GtkListStore *store;
	GtkTreeIter iter;
	GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(main_window, "players_treeview"));
	char *nick, *address, *role, *score, *conn_state;
	int i = 0, ack;
	GtkAdjustment *vadj;
	gchar *ack_icon[] = {"gtk-stop", "gtk-cancel", NULL, "gtk-index", "gtk-apply"};

	DBG_MSG(2, "gui_update_playerlist");

	/* save cursor position */
	vadj = gtk_tree_view_get_vadjustment(treeview);
	
	/* add data to the list store */
	store = gtk_list_store_new (6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	for (i = 0; playerlist_list(&i, &address, &nick, &role, &score, &conn_state, &ack); i++) {
		if (address) {
			DBG_MSG(6, "gui_update_playerlist: adding player \"%s\"", address);
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter,
					0, ack_icon[ack + 2],
					1, nick ? nick : "",
					2, address ? address : "",
					3, role ? role : "",
					4, score ? score : "",
					5, conn_state ? conn_state : "",
					-1);
		}
	}
	g_object_unref(store);

	/* restore position */
	if (vadj)
		gtk_tree_view_set_vadjustment(treeview, vadj);

	gtk_tree_view_columns_autosize(treeview);

}

void gui_store_options_with_info(void) {
	char *err = NULL;

	gui_append_to_chat("-- Ukládám data...");
	if (option_store_to_default()) {
		gui_append_to_chat(" Ok.\n\n");
	} else {
		err = g_locale_to_utf8(strerror(option_last_error), -1, NULL, NULL, NULL);
		gui_append_to_chat(" Chyba: %s.", err);
		g_free(err);
	}
}


void gui_role_clear(void)
{
	static GtkComboBox *c = NULL;
	if (!c) c = GTK_COMBO_BOX(lookup_widget(main_window, "game_role_combobox"));
	gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (c)));
	gtk_combo_box_append_text(c, "pozorovatel");
	gtk_combo_box_set_active(c, 0);
}


void gui_role_add(char *role)
{
	static GtkComboBox *c = NULL;
	assert(role != NULL);
	if (!c) c = GTK_COMBO_BOX(lookup_widget(main_window, "game_role_combobox"));
	gtk_combo_box_append_text(c, role);
}


int gui_exit_question(void)
{
	gint response = GTK_RESPONSE_ACCEPT;
	GtkWidget *d;
	
	if (get_status() != S_OFFLINE) {
		d = gtk_message_dialog_new(GTK_WINDOW(main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
				GTK_BUTTONS_NONE, _("Opravdu ukončit?"));
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(d),
				_("Ukončení programu způsobí uzavření spojení s ostatními hráči"
					" a případně i předčasné ukončení rozehraných her."));
		gtk_dialog_add_buttons(GTK_DIALOG(d),
				GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT,
				GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
				NULL);
		gtk_dialog_set_default_response(GTK_DIALOG(d), GTK_RESPONSE_REJECT);
		response = gtk_dialog_run(GTK_DIALOG(d));
		gtk_widget_destroy(d);
	}

	return response == GTK_RESPONSE_ACCEPT;
}


int gui_config_dialog_from_message(MESSAGE * msg, int notify_target)
{
	return gui_config_dialog_from_message_wp(msg, notify_target,
			msg->src != 'O' && dialog_network_profiles ? dialog_network_profiles : main_window);
}


int gui_config_dialog_from_message_wp(MESSAGE * msg, int notify_target, GtkWidget *parent_window)
{
	GtkWidget *dialog = NULL, *dialog_vbox = NULL, *dialog_action_area = NULL, *button = NULL;
	GtkWidget *frame = NULL, *frame_vbox = NULL, *frame_align = NULL, *frame_label = NULL;
	GtkWidget *hbox = NULL, *label = NULL, *widget = NULL;
	GtkWidget *last_vbox = NULL;
	GtkSizeGroup *label_size_group = NULL;
	int min, max, i, sel;
	
	GUI_ODW_LIST *odw = NULL;
	GUI_ODW *odw_item = NULL;
	GUI_ODW_TYPE widget_type = GUI_ODW_T_NONE;
	
	const char *cat = NULL, *mod = NULL, *option = NULL;
	char *field = NULL, *str = NULL, *val_str = NULL, *title = NULL;
	int val_int;

	assert(msg != NULL);
	assert(parent_window != NULL);

	DBG_MSG(3, "gui_config_dialog_from_message");
	
	/* prepare widget list */
	DBG_MSG(5, "prepare widget list...");
	if (!message_get_next(msg, 1, MESSAGE_SKIP, MESSAGE_STRING, &cat, MESSAGE_STRING, &mod, MESSAGE_STRING, &title, MESSAGE_END)) {
		return 0;
	}
	
	odw = g_malloc(sizeof(GUI_ODW_LIST));
	odw->list = NULL;
	odw->ok_clicked = 0;
	odw->notify_target = msg->src ? msg->src : 0;
	strncpy(odw->cat, cat, OPTION_MAX_CAT_LEN);
	strncpy(odw->mod, mod, OPTION_MAX_MOD_LEN);
	odw->mem_chunk = g_mem_chunk_new("GUI_ODW_LIST", sizeof(GUI_ODW), sizeof(GUI_ODW) * 32, G_ALLOC_ONLY);
	

	/* prepare dialog */
	DBG_MSG(5, "prepare dialog...");
	dialog = gtk_dialog_new();
	str = g_strdup_printf("%s - Net Board", title);
	gtk_window_set_title(GTK_WINDOW(dialog), str);
	g_free(str);
	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
	gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
	gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
	gtk_window_set_default_size (GTK_WINDOW (dialog), 320, -1);
	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
	gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
	dialog_vbox = GTK_DIALOG(dialog)->vbox;

	label_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
	
	last_vbox = dialog_vbox;
	
	DBG_MSG(5, "add widgets...");
	while (message_get_next(msg, 0, MESSAGE_STRING, &field, MESSAGE_END)) {
		
		widget = NULL;
		
		if (!field) {
			DBG_MSG(3, "Missing field!");
			break;
		}

		DBG_MSG(5, "field: \"%s\"", field);

		/* label */
		if (field[0] == '$' || field[0] == '-' || field[0] == '*' || field[0] == '#' || field[0] == '%') {
			hbox = gtk_hbox_new (FALSE, 2);
			gtk_box_pack_start (GTK_BOX (last_vbox), hbox, FALSE, TRUE, 0);

			str = g_strdup_printf("%s:", field + 1);
			label = gtk_label_new_with_mnemonic (str);
			gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
			gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
			gtk_misc_set_padding (GTK_MISC (label), 4, 0);
			g_free(str);
			
			gtk_size_group_add_widget (label_size_group, label);
		}

		switch (field[0]) {
			case '[': /* add frame */
				DBG_MSG(5, "frame");
				frame = gtk_frame_new(NULL);
				gtk_box_pack_start(GTK_BOX(dialog_vbox), frame, FALSE, TRUE, 0);
				gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);

				frame_align = gtk_alignment_new(0.5, 0.5, 1, 1);
				gtk_container_add(GTK_CONTAINER(frame), frame_align);
				gtk_alignment_set_padding(GTK_ALIGNMENT(frame_align), 0, 4, 12, 0);
				
				frame_vbox = gtk_vbox_new(FALSE, 2);
				gtk_container_add(GTK_CONTAINER(frame_align), frame_vbox);

				if (g_utf8_validate(field + 1, -1, NULL))
					str = g_markup_printf_escaped("<b>%s</b>", field + 1);
				else
					str = "??? (invalid UTF-8)";
				frame_label = gtk_label_new(str);
				gtk_frame_set_label_widget(GTK_FRAME(frame), frame_label);
				gtk_label_set_use_markup(GTK_LABEL(frame_label), TRUE);
				g_free(str);
				
				last_vbox = frame_vbox;
				widget = NULL;
				break;
				
			case '=': /* add simple text */
				DBG_MSG(5, "text");
				widget = gtk_label_new (field + 1);
				gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
				gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
				gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
				gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
				gtk_misc_set_padding (GTK_MISC (widget), 4, 4);
				gtk_box_pack_start (GTK_BOX(last_vbox), widget, FALSE, FALSE, 0);
				
				widget = NULL;
				break;

			case '-': /* add text like text entry */
				DBG_MSG(5, "text fake entry");
				if (message_get_next(msg, 0, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_label_new(option ? option : "");
					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_misc_set_alignment (GTK_MISC(widget), 0.0, 0.5);
					gtk_misc_set_padding (GTK_MISC(widget), 0, 2);
					gtk_label_set_selectable (GTK_LABEL(widget), TRUE);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_NONE;
				} else {
					widget = NULL;
				}
				break;

			case '$': /* add text entry */
			case '*': /* add password entry */
				DBG_MSG(5, "text entry");
				if (message_get_next(msg, 0, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_entry_new ();
					if ((val_str = (char*) option_get_string(cat, mod, option)))
						gtk_entry_set_text(GTK_ENTRY(widget), val_str);
					gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);

					if (field[0] == '*')
						gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_ENTRY;
				} else {
					widget = NULL;
				}
				break;

			case '?': /* check button */
				DBG_MSG(5, "check button");
				if (message_get_next(msg, 0, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_check_button_new_with_mnemonic(field + 1);
					val_int = option_get_integer(cat, mod, option);
					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), val_int);
					
					gtk_box_pack_start (GTK_BOX (last_vbox), widget, FALSE, FALSE, 0);
					widget_type = GUI_ODW_T_CHECKBOX;
				} else {
					widget = NULL;
				}
				break;
				
			case '#': /* spin button */
				DBG_MSG(5, "spin button");
				if (message_get_next(msg, 0, MESSAGE_STRING, &option, MESSAGE_INTEGER, &min, MESSAGE_INTEGER, &max, MESSAGE_END)) {
					val_int = option_get_integer(cat, mod, option);
					widget = gtk_spin_button_new_with_range (min, max, 1);
					gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), (gdouble) val_int);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_NUMBER;
				} else {
					widget = NULL;
				}
				break;
				
			case '%': /* combo box */
				if (message_get_next(msg, 0, MESSAGE_STRING, &option, MESSAGE_END)) {
					DBG_MSG(5, "combo box");
					widget = gtk_combo_box_new_text();
					
					i = 0, sel = 0;
					val_str = (char *) option_get_string(odw->cat, odw->mod, option);
					while (message_get_next(msg, 0, MESSAGE_STRING, &str, MESSAGE_END) && str[0]) {
						gtk_combo_box_append_text(GTK_COMBO_BOX(widget), str);
						if (val_str && strcmp(str, val_str) == 0)
							sel = i;
						i++;
					}
					gtk_combo_box_set_active(GTK_COMBO_BOX(widget), sel);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_COMBO;
				} else {
					widget = NULL;
				}
				break;

			default:
				widget = NULL;
		}
		
		DBG_MSG(5, "add widget info to list");
		if(widget && (odw_item = (GUI_ODW *) g_mem_chunk_alloc0(odw->mem_chunk))) {
			odw_item->type = widget_type;
			odw_item->widget = widget;
			strncpy(odw_item->opt, option, OPTION_MAX_OPT_LEN);
			odw_item->opt[OPTION_MAX_OPT_LEN - 1] = 0;
			odw->list = g_slist_prepend(odw->list, (gpointer) odw_item);
		}
	}


	DBG_MSG(5, "adding dialog action area...");

	/* dialog action area */
	dialog_action_area = GTK_DIALOG(dialog)->action_area;
	gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area), GTK_BUTTONBOX_END);

	/* add cancel button */
	button = gtk_button_new_from_stock("gtk-cancel");
	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);

	g_signal_connect_data ((gpointer) button, "clicked", G_CALLBACK (gtk_widget_destroy),
			GTK_OBJECT (dialog), NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);

	/* add ok button */
	button = gtk_button_new_from_stock("gtk-ok");
	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_OK);
	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
	gtk_widget_grab_default(button);
	g_signal_connect ((gpointer) button, "clicked", G_CALLBACK (on_gui_option_ok_button_clicked), (gpointer) odw);
	
	g_signal_connect ((gpointer) dialog, "destroy", G_CALLBACK (on_gui_option_destroy), (gpointer) odw);
	
	/* show it */
	gtk_widget_show_all(dialog);

	/* clean up */
	g_object_unref(G_OBJECT(label_size_group));

	DBG_MSG(3, "Dialog complete.");
	
	return 0;
}


void gui_show_network_profiles (void)
{
	GtkTreeView *treeview;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	int col = 0;

	/* create dialog */
	dialog_network_profiles = create_dialog_network_profiles();
	gtk_window_set_transient_for(GTK_WINDOW(dialog_network_profiles), GTK_WINDOW(main_window));
	
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_network_profiles, "treeview"));
	
	/* column: id */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("ID"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;
	gtk_tree_view_column_set_visible(column, FALSE);

	/* column: name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Název profilu"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;

	/* column: backend */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Síťový modul"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;
	
	/* column: address */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Předvolená adresa"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;

	/* show it */
	gtk_widget_show(dialog_network_profiles);
	gui_update_network_profiles();
}


void gui_update_network_profiles (void)
{
	GtkTreeView *treeview = NULL;
	GtkListStore *store = NULL;
	GtkTreeIter iter;
	char *cat = NULL, *mod = NULL, *opt = NULL;
	int opt_iter = 0;
	char *last_mod = "";
	const char *name = NULL, *backend = NULL, *address = NULL;

	if (!dialog_network_profiles)
		return;
	
	/* assign store */
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_network_profiles, "treeview"));
	store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));

	/* put data */
	for (opt_iter = 0; option_list_opt("network", &opt_iter, &cat, &mod, &opt); opt_iter++) {
		if (cat && mod && opt) {
			if (strcmp(last_mod, mod) != 0) {
				name = option_get_string(cat, mod, "name");
				backend = option_get_string(cat, mod, "backend");
				address = option_get_string(cat, mod, "default_address");
				gtk_list_store_append (store, &iter);
				gtk_list_store_set (store, &iter,
						0, mod ? mod : "",
						1, name ? name : "",
						2, backend ? backend : "",
						3, address ? address : "",
						-1);
			}
			last_mod = mod;
		}
	}

	g_object_unref(store);
	gtk_tree_view_columns_autosize(treeview);
}

void gui_show_network_profile_editor(char *id, GtkWidget *parent_window)
{
	MESSAGE *msg;
	
	assert(id != NULL);
	assert(parent_window != NULL);

	msg = message_create('F', 'O');
	message_append(msg, MESSAGE_STRING, "Odo",
			MESSAGE_STRING, "network", MESSAGE_STRING, id,
			MESSAGE_STRING, _("Úprava síťového profilu"),
			MESSAGE_STRING, _("[Úprava síťového profilu"),
			MESSAGE_STRING, _("-ID Profilu"), MESSAGE_STRING, id,
			MESSAGE_STRING, _("$_Název profilu"), MESSAGE_STRING, "name",
			MESSAGE_STRING, _("$_Síťový modul"), MESSAGE_STRING, "backend",
			MESSAGE_STRING, _("$_Přednastavená adresa"), MESSAGE_STRING, "default_address",
			MESSAGE_STRING, _("%Ú_roveň výpisů"), MESSAGE_STRING, "log_level",
						MESSAGE_STRING, "0: jen chyby",
						MESSAGE_STRING, "1: normální",
						MESSAGE_STRING, "2: verbose",
						MESSAGE_STRING, "3: debug",
						MESSAGE_STRING, "",
			MESSAGE_END);
	gui_config_dialog_from_message_wp(msg, 1, parent_window ? parent_window : main_window);
	message_destroy(msg);
}

void gui_show_network_backend_config(const char *id)
{
	const char *argv[] = { NULL, "-C", NULL, NULL };
	const char *backend = NULL, *dir = NULL;
	gchar *output = NULL, *err_output = NULL;
	int exit_status = 0;
	GError *error = NULL;
	MESSAGE *msg = NULL;
	char *msg_p = NULL;

	backend = option_get_string("network", id, "backend");
	if (backend) {
		argv[0] = backend;
		argv[2] = id;
		dir = option_get_string("main", "dir", "network");
		if (g_spawn_sync(dir, (char **)argv, NULL, 0, NULL, NULL, &output, &err_output, &exit_status, &error)) {
			gui_append_to_netlog("%s\n", err_output);
			msg_p = NULL;
			while ((msg = message_from_string('N', 'O', output, &msg_p))) {
				message_send(msg);
				message_destroy(msg);
			}
		} else {
			gui_show_error_message(main_window, _("Backend nemohl být spuštěn"), _("%s"), error->message);
		}
	}
}

void gui_detach_page(GUI_PAGE page) {
	struct s_gui_page *p = &(gui_page[page]);
	int h, w;
	GdkColor black = { 0, 0, 0, 0 };
	
	option_set_integer("main", "ui", p->option, 1);
	
	if (!p->window)
		p->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	
	if (page != GUI_PAGE_BOARD) {
		h = p->widget->allocation.height;
		w = p->widget->allocation.width;
		gtk_window_set_default_size(GTK_WINDOW(p->window), w < 320 ? 320:w, h < 240 ? 240:h);
	}
	gtk_window_set_title(GTK_WINDOW(p->window), p->win_title);
	gtk_window_set_role(GTK_WINDOW(p->window), p->win_class);
	if (page == GUI_PAGE_BOARD)
		gtk_widget_modify_bg(p->window, GTK_STATE_NORMAL, &black);

	g_signal_connect((gpointer) p->window, "destroy",
			G_CALLBACK(on_detached_widget_destroy),
			(gpointer) p->menuitem);
	
	gtk_widget_hide(p->hide);
	gtk_widget_reparent(p->widget, p->window);
	gtk_widget_show(p->widget);
	gtk_widget_show(p->window);
	gui_update_main_window();
}

void gui_atach_page(GUI_PAGE page) {
	struct s_gui_page *p = &(gui_page[page]);

	option_set_integer("main", "ui", p->option, 0);

	if (p->window) {
		gtk_widget_reparent(p->widget, p->parent);
		gtk_widget_destroy(p->window);
		gtk_widget_show(p->hide);
		p->window = NULL;
	}

	gui_update_main_window();
}

