/*
Copyright (C) 2003 by Sean David Fleming
sean@ivec.org
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.
The GNU GPL can also be found at http://www.gnu.org
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#ifndef __WIN32
#include <sys/times.h>
#endif
#include "gdis.h"
#include "file.h"
#include "matrix.h"
#include "parse.h"
#include "shortcuts.h"
#include "interface.h"
#include "dialog.h"
/* top level data structure */
extern struct sysenv_pak sysenv;
extern GtkWidget *window;
GSList *dir_list=NULL;
GtkListStore *file_path_ts=NULL, *file_name_ts=NULL;
GtkWidget *file_path_tv=NULL, *file_name_tv=NULL;
GtkWidget *curr_path, *file_name;
enum {FILE_PATH, FILE_PATH_NCOLS};
enum {FILE_NAME, FILE_NAME_NCOLS};
/* replacement for dialog_pak */
struct dialog_pak
{
gint type;
gpointer model;
gpointer data;
GHashTable *children;
void (*refresh)(gpointer);
void (*cleanup)(gpointer);
GtkWidget *window;
};
/************************************/
/* callback for destroying a dialog */
/************************************/
void destroy_widget(GtkWidget *w, gpointer target)
{
if (GTK_IS_WIDGET(target))
gtk_widget_destroy(target);
}
/*******************************/
/* dialog extraction primitive */
/*******************************/
gpointer dialog_window(gpointer data)
{
struct dialog_pak *dialog = data;
return(dialog->window);
}
gpointer dialog_model(gpointer data)
{
struct dialog_pak *dialog = data;
return(dialog->model);
}
/************************************/
/* dialog data extraction primitive */
/************************************/
gpointer dialog_child_get(gpointer data, const gchar *key)
{
struct dialog_pak *dialog = data;
gpointer child = NULL;
if (dialog->children)
child = g_hash_table_lookup(dialog->children, key);
return(child);
}
/**********************************/
/* dialog data addition primitive */
/**********************************/
/* used for associating a label with a child widget pointer within a dialog */
void dialog_child_set(gpointer data, const gchar *key, gpointer value)
{
struct dialog_pak *dialog = data;
if (!dialog->children)
dialog->children = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
/* use replace, so old g_strdup() key gets freed */
g_hash_table_replace(dialog->children, g_strdup(key), value);
}
/******************/
/* debugging dump */
/******************/
void dialog_dump(void)
{
gint i=0;
struct dialog_pak *dialog;
GSList *list;
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
printf("[%d] model: %p, type: %d\n", i++, dialog->model, dialog->type);
}
}
/********************************************/
/* cleanup when a dialog has been destroyed */
/********************************************/
#define DEBUG_DIALOG_FREE 0
void dialog_free(GtkWidget *w, gpointer data)
{
struct dialog_pak *dialog = data;
#if DEBUG_DIALOG_FREE
printf("freeing dialog : %p...\n", data);
#endif
if (dialog->cleanup)
dialog->cleanup(dialog->model);
if (dialog->children)
g_hash_table_destroy(dialog->children);
sysenv.dialog_list = g_slist_remove(sysenv.dialog_list, dialog);
g_free(dialog);
}
/***************************/
/* dialog destroy callback */
/***************************/
void dialog_destroy(GtkWidget *w, gpointer data)
{
struct dialog_pak *dialog = data;
gtk_widget_destroy(dialog->window);
}
/***************************/
/* destroy dialogs by type */
/***************************/
void dialog_destroy_type(gint type)
{
GSList *list;
struct dialog_pak *dialog;
list = sysenv.dialog_list;
while (list)
{
dialog = list->data;
list = g_slist_next(list);
if (dialog->type == type)
dialog_destroy(NULL, dialog);
}
}
/***********************************************/
/* destroy all dialogs associated with a model */
/***********************************************/
void dialog_destroy_model(struct model_pak *model)
{
GSList *list;
struct dialog_pak *dialog;
list = sysenv.dialog_list;
while (list)
{
dialog = list->data;
list = g_slist_next(list);
if (dialog->model == model)
dialog_destroy(NULL, dialog);
}
}
/*******************************************************/
/* destroy a given dialog type associated with a model */
/*******************************************************/
void dialog_destroy_single(gint type, struct model_pak *model)
{
GSList *list;
struct dialog_pak *dialog;
list = sysenv.dialog_list;
while (list)
{
dialog = list->data;
list = g_slist_next(list);
if (dialog->type == type && dialog->model == model)
dialog_destroy(NULL, dialog);
}
}
/********************************************/
/* test if a specific type of dialog exists */
/********************************************/
gint dialog_exists(gint type, struct model_pak *model)
{
GSList *list;
struct dialog_pak *dialog;
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
if (model)
{
if (dialog->model == model && dialog->type == type)
return(TRUE);
}
else
{
if (dialog->type == type)
return(TRUE);
}
}
return(FALSE);
}
/******************************/
/* update all current dialogs */
/******************************/
void dialog_refresh_all(void)
{
GSList *list;
struct dialog_pak *dialog;
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
if (dialog->refresh)
dialog->refresh(NULL);
}
}
/***********************************/
/* update dialog of specified type */
/***********************************/
void dialog_refresh_type(gint type)
{
GSList *list;
struct dialog_pak *dialog;
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
if (dialog->type == type)
if (dialog->refresh)
dialog->refresh(NULL);
}
}
/*************************************/
/* update dialogs of specified model */
/*************************************/
void dialog_refresh_model(struct model_pak *model)
{
GSList *list;
struct dialog_pak *dialog;
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
if (dialog->model == model)
if (dialog->refresh)
dialog->refresh(NULL);
}
}
/*****************************/
/* dialog creation primitive */
/*****************************/
#define DEBUG_DIALOG_REQUEST 0
gpointer dialog_request(gint type,
gchar *title,
gpointer refresh,
gpointer cleanup,
struct model_pak *model)
{
GSList *list;
struct dialog_pak *dialog;
#if DEBUG_DIALOG_REQUEST
printf("request to open dialog type : %d, model : %p\n", type, model);
#endif
/* is another of the same type active? */
for (list=sysenv.dialog_list ; list ; list=g_slist_next(list))
{
dialog = list->data;
/* allow only one instance of these dialogs (eg because of globals) */
switch (type)
{
case CREATOR:
case DOCKING:
case GENSURF:
case SURF:
if (type == dialog->type)
{
gdk_window_show((dialog->window)->window);
return(NULL);
}
}
/* type dependent testing */
if (dialog->type == type && dialog->model == model)
{
#if DEBUG_DIALOG_REQUEST
printf(" - Exists...\n");
#endif
/* dialog already open - raise it to the fore & select assoc. model */
gdk_window_show((dialog->window)->window);
if (model)
gui_model_select(model);
return(NULL);
}
}
#if DEBUG_DIALOG_REQUEST
printf(" - Creating...\n");
#endif
/* dialog setup */
dialog = g_malloc(sizeof(struct dialog_pak));
sysenv.dialog_list = g_slist_prepend(sysenv.dialog_list, dialog);
dialog->type = type;
dialog->model = model;
dialog->data = NULL;
dialog->children = NULL;
dialog->refresh = refresh;
dialog->cleanup = cleanup;
/* widget setup */
dialog->window = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog->window), title);
g_signal_connect(GTK_OBJECT(dialog->window), "destroy",
GTK_SIGNAL_FUNC(dialog_free), (gpointer) dialog);
return(dialog);
}
/******************************/
/* safely acquire tree models */
/******************************/
GtkTreeModel *file_path_treemodel(void)
{
if (!file_path_tv)
return(NULL);
if (!GTK_IS_TREE_VIEW(file_path_tv))
return(NULL);
return(gtk_tree_view_get_model(GTK_TREE_VIEW(file_path_tv)));
}
GtkTreeModel *file_name_treemodel(void)
{
if (!file_name_tv)
return(NULL);
if (!GTK_IS_TREE_VIEW(file_name_tv))
return(NULL);
return(gtk_tree_view_get_model(GTK_TREE_VIEW(file_name_tv)));
}
/***************************************/
/* update contents of file load widget */
/***************************************/
#define DEBUG_UPDATE_FILE_PANE 0
gint update_file_pane(void)
{
gint filter;
gchar *name, *full;
GSList *list;
GtkTreeIter iter;
struct stat buff;
/* NEW */
filter = sysenv.file_type;
/* getting from this directory */
gtk_label_set_text(GTK_LABEL(curr_path), sysenv.cwd);
/* clear old data */
gtk_list_store_clear(file_path_ts);
gtk_list_store_clear(file_name_ts);
free_slist(dir_list);
/* get directory listing */
/* NB: success will always return something, even if only ".." */
dir_list = get_dir_list(sysenv.cwd, TRUE);
if (!dir_list)
{
gui_text_show(ERROR, "No directory listing; check your permissions.\n");
gtk_list_store_append(file_path_ts, &iter);
gtk_list_store_set(file_path_ts, &iter, FILE_PATH, "..", -1);
}
list = dir_list;
while (list)
{
/* stat the file (MUST have the full path) */
name = (gchar *) list->data;
full = g_build_filename(sysenv.cwd, list->data, NULL);
stat(full, &buff);
#if DEBUG_UPDATE_FILE_PANE
printf("[%s] : %d\n",full,buff.st_mode);
#endif
/* convert and check if directory */
if ((buff.st_mode & S_IFMT) == S_IFDIR)
{
gtk_list_store_append(file_path_ts, &iter);
gtk_list_store_set(file_path_ts, &iter, FILE_PATH, name, -1);
}
else
{
/* is it a recognized type? */
if (file_extension_valid(list->data))
{
gtk_list_store_append(file_name_ts, &iter);
gtk_list_store_set(file_name_ts, &iter, FILE_NAME, name, -1);
}
#if OLD_GOK /* FIXME: can it be deleted? I haven't changed this code
below to handle empty extensions */
file_data = get_file_info((gpointer *) list->data, BY_EXTENSION);
if (file_data)
{
/* display name if matches current file filter */
if (filter == DATA)
{
/* don't add filetypes with no read/write routines - pictures */
if (file_data->read_file || file_data->write_file)
{
gtk_list_store_append(file_name_ts, &iter);
gtk_list_store_set(file_name_ts, &iter, FILE_NAME, name, -1);
}
}
else
{
/* add if specifically requested (ie even if not in menu) */
if (filter == file_data->group)
{
gtk_list_store_append(file_name_ts, &iter);
gtk_list_store_set(file_name_ts, &iter, FILE_NAME, name, -1);
}
}
}
#endif
}
list = g_slist_next(list);
g_free(full);
}
return(TRUE);
}
/***********************************/
/* change to a specified directory */
/***********************************/
#define DEBUG_SET_PATH 0
gint set_path(const gchar *txt)
{
gint i, n, status=0;
gchar **buff, *text;
GString *path;
/* split by directory separator */
text = g_strdup(txt);
g_strstrip(text);
buff = g_strsplit(text, DIR_SEP, 0);
path = g_string_new(NULL);
/* find the number of tokens */
n=0;
while(*(buff+n))
{
#if DEBUG_SET_PATH
printf("[%s] ", *(buff+n));
#endif
n++;
}
#if DEBUG_SET_PATH
printf(": found %d tokens.\n", n);
#endif
/* truncate token list if parent directory selected */
if (n > 1)
if (g_ascii_strncasecmp("..",*(buff+n-1),2) == 0)
n -= 2;
/* build new path */
/* this is a bit fiddly, as we don't want a dir_sep on the end */
/* EXCEPT if it's the root directory (blame windows for this) */
g_string_sprintf(path, "%s", *buff);
i=1;
while (i < n)
{
g_string_sprintfa(path, "%s%s", DIR_SEP, *(buff+i));
i++;
}
if (n < 2)
g_string_sprintfa(path, "%s", DIR_SEP);
#if DEBUG_SET_PATH
printf("testing path [%s] ... \n", path->str);
#endif
if (g_file_test(path->str, G_FILE_TEST_IS_DIR))
{
if (g_file_test(path->str, G_FILE_TEST_IS_EXECUTABLE))
{
g_free(sysenv.cwd);
sysenv.cwd = g_strdup(path->str);
}
else
{
#if DEBUG_SET_PATH
printf(" Insufficient access permission.\n");
#endif
status++;
}
}
else
{
#if DEBUG_SET_PATH
printf(" Not a directory.\n");
#endif
status++;
}
g_free(text);
g_strfreev(buff);
g_string_free(path, TRUE);
return(status);
}
/*****************************/
/* file type/filter handlers */
/*****************************/
void type_change(GtkWidget *w)
{
G_CONST_RETURN gchar *tmp;
struct file_pak *file_data;
tmp = gtk_entry_get_text(GTK_ENTRY(w));
/* update if valid type */
file_data = get_file_info((gpointer *) tmp, BY_LABEL);
if (file_data)
{
sysenv.file_type = file_data->id;
update_file_pane();
}
}
/********************************************/
/* primary event handler for file selection */
/********************************************/
void file_event_handler(GtkWidget *w,
gpointer secondary_handler(gchar *, struct model_pak *))
{
gchar *name, *fullname;
/* get the current name */
/* NB: we strdup, so we don't have to make name a gconst pointer */
name = g_strdup(gtk_entry_get_text(GTK_ENTRY(file_name)));
/* attempt to use name to change the path */
fullname = g_build_filename(sysenv.cwd, name, NULL);
if (set_path(fullname))
secondary_handler(name, NULL);
g_free(fullname);
g_free(name);
}
/********************************/
/* cartesian/fractional toggles */
/********************************/
void toggle_save_type(GtkWidget *w, struct model_pak *data)
{
data->fractional ^= 1;
}
/**********************/
/* selection handlers */
/**********************/
static void file_path_activate(GtkTreeView *treeview, GtkTreePath *treepath)
{
gchar *text, *path;
GtkTreeIter iter;
GtkTreeModel *treemodel;
treemodel = gtk_tree_view_get_model(treeview);
gtk_tree_model_get_iter(treemodel, &iter, treepath);
gtk_tree_model_get(treemodel, &iter, FILE_PATH, &text, -1);
path = g_build_path(DIR_SEP, sysenv.cwd, text, NULL);
set_path(path);
g_free(text);
g_free(path);
update_file_pane();
}
static void cb_file_name_changed(GtkTreeSelection *selection, gpointer data)
{
gchar *text;
GtkTreeIter iter;
GtkTreeModel *treemodel;
treemodel = file_name_treemodel();
if (!treemodel)
return;
if (gtk_tree_selection_get_selected(selection, &treemodel, &iter))
{
gtk_tree_model_get(treemodel, &iter, FILE_NAME, &text, -1);
gtk_entry_set_text(GTK_ENTRY(file_name), text);
g_free(text);
}
}
static void file_name_activate(GtkTreeView *treeview, GtkTreePath *treepath)
{
gchar *text;
GtkTreeIter iter;
GtkTreeModel *treemodel;
treemodel = gtk_tree_view_get_model(treeview);
gtk_tree_model_get_iter(treemodel, &iter, treepath);
gtk_tree_model_get(treemodel, &iter, FILE_PATH, &text, -1);
file_load(text, NULL);
g_free(text);
}
/*******************/
/* cleanup on exit */
/*******************/
void file_cleanup(void)
{
/* NB: since the tree store is independant of the model's geom list */
/* it must be completely removed (and then restored) with the dialog */
gtk_list_store_clear(file_path_ts);
gtk_list_store_clear(file_name_ts);
free_slist(dir_list);
/* TODO - free row data (ie FILE_PATH/FILE_NAME strings) */
file_path_tv = NULL;
file_path_ts = NULL;
file_name_tv = NULL;
file_name_ts = NULL;
}
/*************************************************/
/* customized load widget (with filetype filter) */
/*************************************************/
void
file_dialog(gchar *title,
gchar *name,
gint type,
gpointer secondary_handler(gchar *, struct model_pak *),
gint filter)
{
gpointer dialog;
GSList *flist;
GList *elist;
GtkWidget *window, *swin, *hbox, *combo, *label;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *select;
struct model_pak *data=NULL;
struct file_pak *fdata;
/* if save type, check we have a loaded model */
if (secondary_handler == (gpointer) file_save_as)
{
data = sysenv.active_model;
if (!data)
return;
}
/* get a dialog if possible */
dialog = dialog_request(FILE_SELECT, "File dialog", NULL, NULL, NULL);
if (!dialog)
return;
window = dialog_window(dialog);
/* make and set up the dialog window */
gtk_window_set_title(GTK_WINDOW(window), title);
gtk_window_set_default_size(GTK_WINDOW(window), 600, 400);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(GTK_DIALOG(window)->vbox)),10);
/* TOP ROW - cwd printed */
hbox = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),hbox,FALSE,FALSE,0);
label = gtk_label_new("Current path: ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
curr_path = gtk_label_new("dummy");
gtk_box_pack_start(GTK_BOX(hbox), curr_path, FALSE, FALSE, 0);
/* option to save as cartesian or fractional coords */
if (secondary_handler == (gpointer) file_save_as)
{
g_assert(data != NULL);
if (data->periodic)
{
hbox = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),
hbox,FALSE,FALSE,0);
new_check_button("Save as cartesian coordinates", toggle_save_type, data,
!data->fractional, hbox);
}
}
/* SECOND ROW - sub directory & file listings */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), hbox, TRUE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(hbox), PANEL_SPACING);
/* scrolled model pane */
swin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (swin),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(hbox), swin, TRUE, TRUE, 0);
/* path treestore/treeview */
file_path_ts = gtk_list_store_new(FILE_PATH_NCOLS, G_TYPE_STRING);
file_path_tv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(file_path_ts));
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), file_path_tv);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Tree", renderer, "text", FILE_PATH, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(file_path_tv), column);
/* NB: use this method instead of selections to handle events */
/* as selections will core dump if the handler clears the store */
g_signal_connect(file_path_tv, "row_activated", G_CALLBACK(file_path_activate), NULL);
/* scrolled model pane */
swin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (swin),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(hbox), swin, TRUE, TRUE, 0);
/* filename treestore/treeview */
file_name_ts = gtk_list_store_new(FILE_NAME_NCOLS, G_TYPE_STRING);
file_name_tv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(file_name_ts));
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), file_name_tv);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Files", renderer, "text", FILE_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(file_name_tv), column);
/* setup the selection handler */
select = gtk_tree_view_get_selection(GTK_TREE_VIEW(file_name_tv));
gtk_tree_selection_set_mode(select, GTK_SELECTION_BROWSE);
/* single click - update entry */
g_signal_connect(G_OBJECT(select), "changed",
G_CALLBACK(cb_file_name_changed),
NULL);
/* double click - automatic load */
if (secondary_handler == (gpointer) file_load)
g_signal_connect(file_name_tv, "row_activated", G_CALLBACK(file_name_activate), NULL);
/* THIRD ROW - filename currently selected & file extension filter */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), hbox, FALSE, FALSE, 0);
/* filename */
file_name = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), file_name, TRUE, TRUE, 0);
if (name)
gtk_entry_set_text(GTK_ENTRY(file_name), name);
gtk_entry_set_editable(GTK_ENTRY(file_name), TRUE);
/* hook a <CR> event to the load action */
g_signal_connect(GTK_OBJECT(file_name), "activate",
GTK_SIGNAL_FUNC(file_event_handler), secondary_handler);
/* build the recognized extension list */
elist = NULL;
flist = sysenv.file_list;
while(flist != NULL)
{
fdata = flist->data;
/* include in menu? */
if (fdata->menu)
elist = g_list_append(elist, fdata->label);
flist = g_slist_next(flist);
}
/* combo box for file filter */
combo = gtk_combo_new();
gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo)->entry), FALSE);
gtk_combo_set_popdown_strings(GTK_COMBO(combo), elist);
/* set the currently selected type (BEFORE the changed event is connected) */
fdata = get_file_info(GINT_TO_POINTER(filter), BY_FILE_ID);
if (fdata)
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), fdata->label);
gtk_box_pack_start(GTK_BOX (hbox), combo, TRUE, TRUE, 0);
g_signal_connect(GTK_OBJECT(GTK_COMBO(combo)->entry), "changed",
GTK_SIGNAL_FUNC(type_change), NULL);
gtk_widget_set_size_request(combo, 6*sysenv.gtk_fontsize, -1);
/* terminating buttons */
switch (type)
{
case FILE_LOAD:
gui_stock_button(GTK_STOCK_OPEN, file_event_handler, secondary_handler,
GTK_DIALOG(window)->action_area);
break;
case FILE_SAVE:
gui_stock_button(GTK_STOCK_SAVE, file_event_handler, secondary_handler,
GTK_DIALOG(window)->action_area);
break;
}
gui_stock_button(GTK_STOCK_CANCEL, dialog_destroy, dialog,
GTK_DIALOG(window)->action_area);
/* all done */
gtk_widget_show_all(window);
sysenv.file_type = filter;
update_file_pane();
}
/*************************************************/
/* callback to update a widget background colour */
/*************************************************/
void set_colour_widget(GtkWidget *cs, GtkWidget *w)
{
GdkColor colour;
if (GTK_IS_WIDGET(cs))
gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(cs), &colour);
if (GTK_IS_WIDGET(w))
gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &colour);
}
/***************************************/
/* callback to update the colour value */
/***************************************/
void set_colour_value(GtkWidget *cs, gdouble *x)
{
GdkColor colour;
gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(cs), &colour);
x[0] = colour.red;
x[1] = colour.green;
x[2] = colour.blue;
VEC3MUL(x, 1.0/65535.0);
}
/**********************************/
/* create a colour editing dialog */
/**********************************/
void dialog_colour_new(GtkWidget *w, gdouble *colour)
{
GtkWidget *csd;
/* create colour selection dialog */
csd = gtk_color_selection_dialog_new("Edit colour");
/* set the initial colour */
gtk_color_selection_set_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(csd)->colorsel), colour);
/* value colour update */
g_signal_connect(GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(csd)->colorsel), "color_changed",
GTK_SIGNAL_FUNC(set_colour_value), (gpointer) colour);
/* widget colour update */
if (w)
g_signal_connect(GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(csd)->colorsel), "color_changed",
GTK_SIGNAL_FUNC(set_colour_widget), (gpointer) w);
g_signal_connect(GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(csd)->ok_button), "clicked",
GTK_SIGNAL_FUNC(destroy_widget), (gpointer) csd);
gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(csd)->cancel_button);
gtk_widget_show(csd);
/*
g_signal_connect(GTK_OBJECT(w), "destroy", GTK_SIGNAL_FUNC(destroy_widget), csd);
*/
}
syntax highlighted by Code2HTML, v. 0.9.1