/***********************************************************************
* link_config.c : Implementation of a group of widgets that allow the user
* to view and edit a link drawing rules list.
***********************************************************************/
/***********************************************************************
* This file is part of SpaceChart.
* Copyright (C) 2000 Miguel Coca <e970095@zipi.fi.upm.es>
*
* 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 <stdlib.h>
#include "../include/starmap.h"
#include "../include/link.h"
#include "../include/link_selection.h"
#include "../include/link_draw_rules.h"
#include "../include/link_config.h"
struct st_list_data
{
int is_default;
double max_length;
int width;
GdkLineStyle style;
double rgb[3];
};
struct st_rule_dialog
{
GtkWidget *dialog;
GtkWidget *color_picker;
GtkObject *width_adj;
GtkObject *max_length_adj;
GtkWidget *solid_button;
GtkWidget *dashed_button;
};
struct st_link_conf
{
link_drawing_rules_t *rules;
GtkWidget *main_widget;
GtkWidget *list;
GtkWidget *edit_button;
GtkWidget *del_button;
distance_unit_t unit;
void (*changed)( link_config_t *config, void *data );
void *changed_data;
struct st_rule_dialog *rule_dialog;
int current_row;
};
/* Declaration of Private Functions */
static void cb_insert_rule( link_selection_t* selection, int width,
GdkLineStyle style, double rgb[],
link_config_t* config );
static GdkPixmap* make_rule_pixmap( GtkWidget *widget, int width,
GdkLineStyle style, double rgb[] );
static void cb_edit_rule( GtkWidget *button, link_config_t *config );
static void cb_add_rule( GtkWidget *button, link_config_t *config );
static void cb_delete_rule( GtkWidget *button, link_config_t *config );
static struct st_rule_dialog *create_rule_dialog( struct st_list_data *data,
link_config_t *config );
static void cb_changed_color( GtkWidget *widget, guint r, guint g, guint b,
guint a, struct st_rule_dialog *dialog );
static void cb_changed_size(GtkAdjustment *adj, struct st_rule_dialog *dialog);
static void cb_toggled_style(GtkWidget *widget, struct st_rule_dialog *dialog);
static void cb_apply_edit( GnomePropertyBox *box, int page_num,
link_config_t *config );
static void cb_apply_add( GnomePropertyBox *box, int page_num,
link_config_t *config );
static void cb_select_row( GtkWidget *widget, gint row, gint column,
GdkEventButton *event, link_config_t *config );
static void cb_unselect_row( GtkWidget *widget, gint row, gint column,
GdkEventButton *event, link_config_t *config );
/* Public functions */
link_config_t* link_config_new( void (*changed)( link_config_t *config,
void *data ), void *data )
{
link_config_t *config;
GtkWidget *table, *add_button;
char *titles[] = {_("Max Length"),_("Example")};
if( (config = (link_config_t*) malloc(sizeof(link_config_t))) )
{
config->changed = changed;
config->changed_data = data;
config->rules = NULL;
config->current_row = 0;
table = gtk_table_new( 2, 3, FALSE );
gtk_container_border_width(GTK_CONTAINER(table),5);
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
gtk_table_set_col_spacings(GTK_TABLE(table), 5);
config->main_widget = gtk_frame_new( _("Links by length") );
gtk_container_border_width(GTK_CONTAINER(config->main_widget),10);
config->list = gtk_clist_new_with_titles( 2, titles );
gtk_clist_set_selection_mode( GTK_CLIST(config->list),
GTK_SELECTION_SINGLE );
gtk_clist_column_titles_passive( GTK_CLIST(config->list) );
gtk_signal_connect( GTK_OBJECT(config->list), "select_row",
cb_select_row, config );
gtk_signal_connect( GTK_OBJECT(config->list), "unselect_row",
cb_unselect_row, config );
add_button = gtk_button_new_with_label(_("Add Rule"));
gtk_signal_connect( GTK_OBJECT(add_button), "clicked",
cb_add_rule, config );
config->del_button=gtk_button_new_with_label(_("Delete Rule"));
gtk_widget_set_sensitive( config->del_button, FALSE );
gtk_signal_connect( GTK_OBJECT(config->del_button), "clicked",
cb_delete_rule, config );
config->edit_button=gtk_button_new_with_label(_("Edit Rule"));
gtk_widget_set_sensitive( config->edit_button, FALSE );
gtk_signal_connect( GTK_OBJECT(config->edit_button), "clicked",
cb_edit_rule, config );
gtk_container_add( GTK_CONTAINER(config->main_widget), table );
gtk_table_attach_defaults( GTK_TABLE(table), config->list,
0, 3, 0, 1 );
gtk_table_attach( GTK_TABLE(table), add_button, 0, 1, 1, 2,
(GtkAttachOptions) GTK_FILL | GTK_EXPAND,
(GtkAttachOptions) 0, 0, 0 );
gtk_table_attach( GTK_TABLE(table), config->edit_button,
1, 2, 1, 2,
(GtkAttachOptions) GTK_FILL | GTK_EXPAND,
(GtkAttachOptions) 0, 0, 0 );
gtk_table_attach( GTK_TABLE(table), config->del_button,
2, 3, 1, 2,
(GtkAttachOptions) GTK_FILL | GTK_EXPAND,
(GtkAttachOptions) 0, 0, 0 );
}
return config;
}
void link_config_set_rules( link_config_t* config,
link_drawing_rules_t* rules )
{
int width;
GdkLineStyle style;
double rgb[3];
link_selection_t *selection;
config->rules = rules;
/* First, the default rule. */
link_drawing_rules_get_default( rules, &width, &style, rgb );
selection = link_selection_new();
cb_insert_rule( selection, width, style, rgb, config );
/* Insert all the others. */
link_drawing_rules_foreach( rules,
(void(*)( link_selection_t*,int,
GdkLineStyle,double*,void*))
cb_insert_rule, config );
}
void link_config_set_unit( link_config_t* config,
distance_unit_t unit )
{
config->unit = unit;
}
GtkWidget* link_config_get_widget( link_config_t* config )
{
return config->main_widget;
}
link_drawing_rules_t* link_config_get_rules(link_config_t* config)
{
int row;
struct st_list_data *data;
link_drawing_rules_t *rules;
link_selection_t *selection;
double prev = 0;
/* Find the default rule.
* FIXME: Is there a way to tell how many rows there are in the list?*/
for( row = 0; !((struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), row))->is_default; row++ )
;
data = (struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list),row);
rules = link_drawing_rules_new( data->width, data->style, data->rgb );
for( row = 0; !((struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), row))->is_default; row++ )
{
data = (struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list),row);
selection = link_selection_new();
link_selection_act_min_length( selection, prev );
link_selection_act_max_length( selection, data->max_length );
link_drawing_rules_add( rules, selection, data->width,
data->style, data->rgb );
prev = data->max_length;
}
return rules;
}
void link_config_destroy( link_config_t* conf )
{
free( conf );
}
/* Private Functions */
void cb_insert_rule( link_selection_t* selection, int width,
GdkLineStyle style, double rgb[], link_config_t* config )
{
int row;
char *text[2];
char max_length[10];
struct st_list_data *data = g_malloc(sizeof(struct st_list_data));
data->is_default = !(link_selection_is_max_length(selection) ||
link_selection_is_max_length(selection) );
data->max_length = link_selection_get_max_length(selection);
data->width = width;
data->style = style;
data->rgb[0] = rgb[0];
data->rgb[1] = rgb[1];
data->rgb[2] = rgb[2];
sprintf( max_length, "%5.2f", config->unit==DISTANCE_PARSECS ?
data->max_length : data->max_length * PARSEC_TO_LY );
text[0] = max_length;
text[1] = NULL;
if( data->is_default )
{
text[0] = _("Infinite");
row = gtk_clist_append( GTK_CLIST(config->list), text );
gtk_clist_set_pixmap(GTK_CLIST(config->list), row, 1,
make_rule_pixmap(config->list,width,
style,rgb), NULL);
gtk_clist_set_row_data( GTK_CLIST(config->list), row, data );
}
else
{
for( row = 0; !((struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), row))->is_default; row++ )
if( ((struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), row))->max_length >
data->max_length )
break;
gtk_clist_insert( GTK_CLIST(config->list), row, text );
gtk_clist_set_pixmap(GTK_CLIST(config->list), row, 1,
make_rule_pixmap(config->list,width,
style,rgb), NULL);
gtk_clist_set_row_data( GTK_CLIST(config->list), row, data );
}
}
GdkPixmap* make_rule_pixmap( GtkWidget *widget, int width, GdkLineStyle style,
double rgb[] )
{
GdkPixmap* pixmap;
GdkGC* gc;
GdkColor color;
gtk_widget_realize( widget );
gc = gdk_gc_new( widget->window );
color.red = (guint16) ( rgb[0] * 65535.0 );
color.green = (guint16) ( rgb[1] * 65535.0 );
color.blue = (guint16) ( rgb[2] * 65535.0 );
color.pixel = (gulong) color.red * 65536 +
color.green * 256 + color.blue;
gdk_color_alloc( gtk_widget_get_colormap(widget), &color );
gdk_gc_set_foreground( gc, &color );
gdk_gc_set_line_attributes( gc, width, style,
GDK_CAP_BUTT,
GDK_JOIN_MITER );
pixmap = gdk_pixmap_new( widget->window, 50, 20, -1);
gdk_draw_rectangle( pixmap, widget->style->black_gc,
TRUE, 0, 0, 50, 20 );
gdk_draw_line( pixmap, gc, 6, 10, 44, 10 );
gdk_gc_destroy( gc );
return pixmap;
}
void cb_edit_rule( GtkWidget *button, link_config_t *config )
{
struct st_list_data *data;
data = (struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), config->current_row);
config->rule_dialog = create_rule_dialog( data, config );
gtk_signal_connect( GTK_OBJECT(config->rule_dialog->dialog), "apply",
cb_apply_edit, config );
gnome_dialog_run_and_close(GNOME_DIALOG(config->rule_dialog->dialog));
free(config->rule_dialog);
}
void cb_add_rule( GtkWidget *button, link_config_t *config )
{
struct st_list_data *data;
data = (struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), config->current_row);
config->rule_dialog = create_rule_dialog( data, config );
gtk_signal_connect( GTK_OBJECT(config->rule_dialog->dialog), "apply",
cb_apply_add, config );
gnome_dialog_run_and_close(GNOME_DIALOG(config->rule_dialog->dialog));
free(config->rule_dialog);
}
void cb_delete_rule( GtkWidget *button, link_config_t *config )
{
gtk_clist_remove( GTK_CLIST(config->list), config->current_row );
config->changed(config, config->changed_data);
}
struct st_rule_dialog *create_rule_dialog( struct st_list_data *data,
link_config_t *config )
{
struct st_rule_dialog *dialog;
GtkWidget *table, *label, *width_spin, *maxl_spin;
if( !(dialog = malloc( sizeof(struct st_rule_dialog) )) )
return NULL;
dialog->dialog = gnome_property_box_new();
/* Color */
dialog->color_picker = gnome_color_picker_new();
gnome_color_picker_set_d(GNOME_COLOR_PICKER(dialog->color_picker),
data->rgb[0], data->rgb[1], data->rgb[2],0.0);
gtk_signal_connect( GTK_OBJECT(dialog->color_picker),
"color_set", cb_changed_color, dialog );
/* Width */
dialog->width_adj = gtk_adjustment_new( data->width, 0, 5, 1, 1, 0.0);
width_spin = gtk_spin_button_new( GTK_ADJUSTMENT(
dialog->width_adj), 1, 0);
gtk_signal_connect(GTK_OBJECT(dialog->width_adj), "value_changed",
GTK_SIGNAL_FUNC(cb_changed_size), dialog);
/* Max Length */
dialog->max_length_adj = gtk_adjustment_new(
config->unit==DISTANCE_PARSECS ? data->max_length :
data->max_length * PARSEC_TO_LY, 0,100,0.1,1,0.0);
maxl_spin = gtk_spin_button_new( GTK_ADJUSTMENT(
dialog->max_length_adj), 0.01, 2);
gtk_signal_connect(GTK_OBJECT(dialog->max_length_adj), "value_changed",
GTK_SIGNAL_FUNC(cb_changed_size), dialog);
gtk_widget_set_sensitive(maxl_spin, !data->is_default );
/* The style */
dialog->solid_button = gtk_radio_button_new_with_label(NULL,_("Solid Line"));
dialog->dashed_button = gtk_radio_button_new_with_label(
gtk_radio_button_group(GTK_RADIO_BUTTON(dialog->solid_button)),
_("Dashed Line") );
if( data->style == GDK_LINE_SOLID )
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(
dialog->solid_button), TRUE);
else
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(
dialog->dashed_button), TRUE);
gtk_signal_connect( GTK_OBJECT(dialog->solid_button), "toggled",
cb_toggled_style, dialog );
gtk_signal_connect( GTK_OBJECT(dialog->dashed_button), "toggled",
cb_toggled_style, dialog );
/* Pack */
table = gtk_table_new( 4, 2, TRUE );
gtk_container_border_width(GTK_CONTAINER(table),10);
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
gtk_table_set_col_spacings(GTK_TABLE(table), 5);
label = gtk_label_new( _("Edit Rule") );
gnome_property_box_append_page( GNOME_PROPERTY_BOX(dialog->dialog),
table, label );
label = gtk_label_new( _("Link Max Length") );
gtk_table_attach( GTK_TABLE(table), label, 0, 1, 0, 1,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_table_attach( GTK_TABLE(table), maxl_spin, 1, 2, 0, 1,
(GtkAttachOptions) 0, (GtkAttachOptions) 0,
0, 0 );
label = gtk_label_new( _("Link Width") );
gtk_table_attach( GTK_TABLE(table), label, 0, 1, 1, 2,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_table_attach( GTK_TABLE(table), width_spin, 1, 2, 1, 2,
(GtkAttachOptions) 0, (GtkAttachOptions) 0,
0, 0 );
label = gtk_label_new( _("Link Color") );
gtk_table_attach( GTK_TABLE(table), label, 0, 1, 2, 3,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_table_attach( GTK_TABLE(table), dialog->color_picker, 1, 2, 2, 3,
(GtkAttachOptions) 0, (GtkAttachOptions) 0,
0, 0 );
gtk_table_attach( GTK_TABLE(table), dialog->solid_button, 0, 1, 3, 4,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
(GtkAttachOptions) GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_table_attach( GTK_TABLE(table), dialog->dashed_button, 1, 2, 3, 4,
(GtkAttachOptions) 0, (GtkAttachOptions) 0,
0, 0 );
gtk_widget_show_all( dialog->dialog );
return dialog;
}
void cb_changed_color( GtkWidget *widget, guint r, guint g, guint b,
guint a, struct st_rule_dialog *dialog )
{
gnome_property_box_changed( GNOME_PROPERTY_BOX(dialog->dialog) );
}
void cb_changed_size( GtkAdjustment *adj, struct st_rule_dialog *dialog )
{
gnome_property_box_changed( GNOME_PROPERTY_BOX(dialog->dialog) );
}
void cb_toggled_style(GtkWidget *widget, struct st_rule_dialog *dialog)
{
gnome_property_box_changed( GNOME_PROPERTY_BOX(dialog->dialog) );
}
void cb_apply_edit( GnomePropertyBox *box, int page_num,link_config_t *config )
{
int width;
double max_length;
double rgb[3];
GdkLineStyle style;
link_selection_t *selection;
int is_default;
if( page_num != -1 )
return;
gtk_clist_freeze( GTK_CLIST(config->list) );
is_default = ((struct st_list_data*)gtk_clist_get_row_data(
GTK_CLIST(config->list), config->current_row))->is_default;
gtk_clist_remove( GTK_CLIST(config->list), config->current_row );
width = GTK_ADJUSTMENT(config->rule_dialog->width_adj)->value;
max_length=GTK_ADJUSTMENT(config->rule_dialog->max_length_adj)->value;
max_length = config->unit==DISTANCE_PARSECS ? max_length :
max_length / PARSEC_TO_LY;
gnome_color_picker_get_d( GNOME_COLOR_PICKER(
config->rule_dialog->color_picker), rgb, rgb+1, rgb+2, NULL );
if( gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(config->rule_dialog->solid_button)) )
style = GDK_LINE_SOLID;
else
style = GDK_LINE_ON_OFF_DASH;
selection = link_selection_new();
if( !is_default )
link_selection_act_max_length( selection, max_length );
cb_insert_rule( selection, width, style, rgb, config );
link_selection_destroy( selection );
gtk_clist_thaw( GTK_CLIST(config->list) );
config->changed(config, config->changed_data);
}
void cb_apply_add( GnomePropertyBox *box, int page_num,link_config_t *config )
{
int width;
double max_length;
double rgb[3];
GdkLineStyle style;
link_selection_t *selection;
if( page_num != -1 )
return;
gtk_clist_freeze( GTK_CLIST(config->list) );
width = GTK_ADJUSTMENT(config->rule_dialog->width_adj)->value;
max_length=GTK_ADJUSTMENT(config->rule_dialog->max_length_adj)->value;
max_length = config->unit==DISTANCE_PARSECS ? max_length :
max_length / PARSEC_TO_LY;
gnome_color_picker_get_d( GNOME_COLOR_PICKER(
config->rule_dialog->color_picker), rgb, rgb+1, rgb+2, NULL );
if( gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(config->rule_dialog->solid_button)) )
style = GDK_LINE_SOLID;
else
style = GDK_LINE_ON_OFF_DASH;
selection = link_selection_new();
link_selection_act_max_length( selection, max_length );
cb_insert_rule( selection, width, style, rgb, config );
link_selection_destroy( selection );
gtk_clist_thaw( GTK_CLIST(config->list) );
config->changed(config, config->changed_data);
}
void cb_select_row( GtkWidget *widget, gint row, gint column,
GdkEventButton *event, link_config_t *config )
{
config->current_row = row;
gtk_widget_set_sensitive( config->del_button,
!((struct st_list_data*)
gtk_clist_get_row_data(GTK_CLIST(config->list), row))->is_default );
gtk_widget_set_sensitive( config->edit_button, TRUE );
}
void cb_unselect_row( GtkWidget *widget, gint row, gint column,
GdkEventButton *event, link_config_t *config )
{
gtk_widget_set_sensitive( config->del_button, FALSE );
gtk_widget_set_sensitive( config->edit_button, FALSE );
}
syntax highlighted by Code2HTML, v. 0.9.1