/* sf_control.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include "getopt.h" #include "sf.h" /* for iconify_window(): */ #include #include #include #include /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static gchar* author = "donald johnson"; static gchar* company = "dla.kwi Ensign Core"; #define MAX_NAME ( MAX_KEY / 2 ) #define MAX_GENERATION 24 /* " -FFFFFFFF .. +FFFFFFFF " */ #define MAX_FILESPEC 128 #define DEF_GENERATION "?" /* i.e. random */ #define PAD 4 /* widget padding */ #define BORDER 8 /* widget border width */ #define PING_INTERVAL 5000 /* milliseconds */ #define BUTTON_PRESS_INTERVAL 250 #undef QUIT_ON_OVERRUN /* define to quit on generation overrun */ #define MIN_SPEED 1.0 #define DEF_SPEED 20.0 #define MAX_SPEED 120.0 #define SPEED_STEP 1.0 #define SPEED_PAGE 10.0 #define MIN_BANDING 2.0 #define DEF_BANDING 5.0 #define MAX_BANDING 9.0 #define BANDING_STEP 1.0 #define BANDING_PAGE 2.0 #define MIN_CENTRE 0.0 #define DEF_CENTRE 8.0 #define MAX_CENTRE 24.0 #define CENTRE_STEP 1.0 #define CENTRE_PAGE 4.0 /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* generation method */ typedef enum { method_NULL = -1, method_Named = 0, /* this is the notebook page creation order */ method_Automatic = 1, /* */ method_List = 2 /* */ } method_e; /* Generation state */ typedef enum { gen_state_Stopped = 0, gen_state_Running = 1, gen_state_Error = 2 } gen_state_e; /* Control state */ typedef enum { state_Specifying = 0, state_Generating = 1, state_Viewing = 2, state_Error = 3 } state_e; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static int control_pid; /* Control process id */ static int generation_pid; /* Generation process id */ static int view_pid; /* View process id */ static msg_pipe g_mp; /* Control <-> Generation pipe */ static msg_pipe v_mp; /* Control <-> View pipe */ static char* img_image; /* shared memory XPM image */ static int img_sem; /* image mutex */ static gint children_timer = 0; /* child processes timer */ static gint g_ping = 0; /* Generation ping count */ static gint v_ping = 0; /* View ping count */ static gint button_timer; static gint g_input_tag = -1; /* Generation input handle */ static gint v_input_tag = -1; /* View input handle */ static state_e state = state_Specifying; /* current Control state */ static gen_state_e gen_state = gen_state_Stopped; static gchar gen_key[MAX_KEY+1]; static gint gen_size; static gint generations = 0; /* how many generations? */ /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #define SETTINGS 6 /* option menu */ typedef struct { char* label; int id; } option_t; static option_t size_table[SIZES] = { { "32 x 32", size_032x032 }, { "64 x 64", size_064x064 }, { "128 x 128", size_128x128 }, { "256 x 256", size_256x256 }, { "512 x 512", size_512x512 } }; static option_t symmetry_table[SYMMETRIES] = { { "vertical", symmetry_VERTICAL }, { "horizontal", symmetry_HORIZONTAL } }; static option_t loop_table[LOOPS] = { { "Once", loop_ONCE }, { "Repeat", loop_REPEAT } }; static option_t edges_table[EDGES] = { { "No", edges_NO }, { "Gray", edges_GRAY }, { "Solid Gray", edges_GRAY_SOLID }, { "Yes", edges_YES } }; static option_t colour_scheme_table[COLOUR_SCHEMES] = { { "White on Black", colour_scheme_WHITE_ON_BLACK }, { "Black on White", colour_scheme_BLACK_ON_WHITE } }; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static GtkWidget* snowflake_window; static GtkWidget* error_dialog; static gchar error_message[512]; static GtkWidget* size_option_menu; static GtkWidget* size_menu; static int size = size_256x256; static GtkWidget* symmetry_option_menu; static GtkWidget* symmetry_menu; static int symmetry = symmetry_VERTICAL; static GtkWidget* edges_option_menu; static GtkWidget* edges_menu; static int edges = edges_YES; static GtkWidget* colour_option_menu; static GtkWidget* colour_menu; static int colour_scheme = colour_scheme_WHITE_ON_BLACK; static GtkWidget* banding_spin; static int banding = DEF_BANDING; static GtkWidget* centre_spin; static int centre = DEF_CENTRE; /* -------------------------------- */ static GtkWidget* notebook; static method_e method = method_Named; /* -------------------------------- */ /* named method */ static GtkWidget* named_page; static GtkWidget* named_label; static GtkWidget* named_Name; static GtkWidget* named_Draw_button; static GtkWidget* named_Permute_button; static GtkWidget* named_Make_Key_button; /* -------------------------------- */ /* automatic method */ static GtkWidget* automatic_page; static GtkWidget* automatic_label; static GtkWidget* automatic_Key; static GtkWidget* automatic_Generation; static GtkWidget* automatic_Speed; static GtkWidget* automatic_Draw_button; static GtkWidget* automatic_Next_button; static GtkWidget* automatic_Run_button; static GtkWidget* automatic_Stop_button; static gint automatic_timer = 0; static gint automatic_count; /* -------------------------------- */ /* list method */ static GtkWidget* list_page; static GtkWidget* list_label; static GtkWidget* list_Filespec; static char list_filespec[MAX_FILESPEC+1]; static GtkWidget* list_Speed; static GtkWidget* list_option_Loop; static GtkWidget* list_Loop; static GtkWidget* list_Open_button; static GtkWidget* list_Run_button; static GtkWidget* list_Stop_button; static int loop = loop_REPEAT; static int list_timer = 0; static int list_count; static int list_line; static FILE* list_file = (FILE*)0; /* -------------------------------- */ static GtkWidget* Quit_button; static GtkWidget* Save_Image_button; static GtkWidget* Save_Design_button; static GtkWidget* Add_Design_button; static GtkWidget* About_button; static GtkWidget* About_dialog; static char xpm_filespec[MAX_FILESPEC+1] = { 0 }; static char design_filespec[MAX_FILESPEC+1] = { 0 }; static signed char design_line = -1; static FILE* design_file = (FILE*)0; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* prototypes */ static void control_Exit ( int send_g_QUIT,int send_v_QUIT ); static void control_Quit ( GtkWidget* widget,GtkWidget* window ); static gint control_Close ( GtkWidget* widget, GdkEvent* event, gpointer* data ); static gint ping_children( gpointer data ); static gint press_button( gpointer data ); static void generate( gchar* key, gint size, gint symmetry, gint edges, gint colour_scheme, gint banding, gint centre ); static void g_input_Callback( gpointer clientdata, gint source, GdkInputCondition condition ); static void v_input_Callback( gpointer clientdata, gint source, GdkInputCondition condition ); static gint filter_key( gchar* old_key,gchar* new_key ); static gint filter_generation( gchar* generation, gchar* step,gchar* lo,gchar* hi ); static void set_random_key( gchar* step_text,gint digits ); static void set_random_range( gchar* step_text, gchar* lo_text,gchar* hi_text,gint digits ); static gint xtoi( gchar* number_text ); static void twos_complement( gchar* not_number_text,gchar* number_text ); static void add_to_xstring( gchar* sum_text,gchar* number_text ); static void shift_xstring( gchar* new_key_text,gchar* shift_text ); static void set_Settings_Sensitive( gint sensitive ); static void size_Select_Callback( GtkWidget* widget,gpointer data ); static void symmetry_Select_Callback( GtkWidget* widget,gpointer data ); static void edges_Select_Callback( GtkWidget* widget,gpointer data ); static void colour_scheme_Select_Callback( GtkWidget* widget,gpointer data ); static void method_Switch( GtkWidget* widget, GtkNotebookPage* page,gint page_num ); static void named_Enter_Callback( GtkWidget* widget,GtkWidget* entry ); static void named_Draw_Callback( GtkWidget* widget,GtkWidget* window ); static void named_Permute_Callback( GtkWidget* widget,GtkWidget* window ); static void named_Make_Key_Callback( GtkWidget* widget,GtkWidget* window ); static void hash_key( gchar* key,gchar* name ); static void automatic_Enter_Callback( GtkWidget* widget,GtkWidget* entry ); static void automatic_Draw_Callback( GtkWidget* widget,GtkWidget* window ); static void automatic_Next_Callback( GtkWidget* widget,GtkWidget* window ); static void automatic_Run_Callback( GtkWidget* widget,GtkWidget* window ); static void automatic_Stop_Callback( GtkWidget* widget,GtkWidget* window ); static void automatic_Next_one( void ); static gint automatic_timeout( gpointer data ); static gint generate_next_generation( char* generation_text, gint* step,gint* lo,gint* hi ); static void loop_Select_Callback( GtkWidget* widget,gpointer data ); static void open_design_file_chosen( GtkWidget* w,GtkFileSelection* fs ); static void open_design_file_choice_cancelled( GtkWidget* w, GtkFileSelection* fs ); static void list_Open_Callback( GtkWidget* widget,GtkWidget* window ); static void list_Run_Callback( GtkWidget* widget,GtkWidget* window ); static void list_Stop_Callback( GtkWidget* widget,GtkWidget* window ); static gint list_read_one( void ); static gint list_timeout( gpointer data ); static void image_file_chosen( GtkWidget* w,GtkFileSelection* fs ); static void image_file_choice_cancelled( GtkWidget* w,GtkFileSelection* fs ); static void control_Save_Image( GtkWidget* widget,GtkWidget* window ); static void hide_selection_fileops( GtkWidget* widget,GtkFileSelection* fs ); static void design_file_chosen( GtkWidget* w,GtkFileSelection* fs ); static void design_file_choice_cancelled( GtkWidget* w,GtkFileSelection* fs ); static void control_Save_Design( GtkWidget* widget,GtkWidget* window ); static void control_Add_Design( GtkWidget* widget,GtkWidget* window ); static void add_design_error_Callback( GtkWidget* widget,GtkWidget* window ); static void control_About( GtkWidget* widget,GtkWidget* window ); static void About_OK_Callback( GtkWidget* widget,GtkWidget* window ); static method_e apply_args( int argc,char* argv[] ); static void build_Control_Window( void ); static void error_Dialog( gchar* message ); static void error_Callback( GtkWidget* widget,GtkWidget* window ); static void iconify_window( GtkWidget* window ); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ void control_main( int argc, char* argv[], msg_pipe generation, msg_pipe view, int image_semid, char* image ) { time_t current_time; method_e command_method; /* save arguments */ g_mp = generation; v_mp = view; img_sem = image_semid; img_image = image; /* save Control process id */ control_pid = getpid(); /* seed random number generator */ current_time = time( (time_t*)0 ); srandom( (unsigned int)current_time ); /* start gtk */ gtk_init( &argc,&argv ); /* build the Control interface */ build_Control_Window(); /* check for command line options */ command_method = apply_args( argc,argv ); /* start the child process check */ children_timer = gtk_timeout_add( PING_INTERVAL, ping_children, 0 ); /* look for input from the Generation process */ g_input_tag = gdk_input_add( g_mp.rcv, GDK_INPUT_READ, g_input_Callback, (gpointer)g_mp.rcv ); /* look for input from the View process */ v_input_tag = gdk_input_add( v_mp.rcv, GDK_INPUT_READ, v_input_Callback, (gpointer)v_mp.rcv ); if ( command_method != method_NULL ) button_timer = gtk_timeout_add( BUTTON_PRESS_INTERVAL, press_button, (gpointer)command_method ); /* start */ gtk_main(); /* quit */ control_Exit( TRUE,TRUE ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* quit, cleaning up before we go */ static void control_Exit( int send_g_QUIT,int send_v_QUIT ) { snowflake_message msg; if ( children_timer ) gtk_timeout_remove( children_timer ); children_timer = 0; /* tell the Generation process to quit? */ if ( send_g_QUIT && g_ping == 0 ) { msg.cmd = cmd_QUIT; snd_msg( g_mp,&msg ); } /* tell the View process to quit? */ if ( send_v_QUIT && v_ping == 0 ) { msg.cmd = cmd_QUIT; snd_msg( v_mp,&msg ); } /* no more Generation input */ if ( g_input_tag != -1 ) gdk_input_remove( g_input_tag ); /* no more View input */ if ( v_input_tag != -1 ) gdk_input_remove( v_input_tag ); /* if the automatic method is still running, stop it */ if ( automatic_timer ) gtk_timeout_remove( automatic_timer ); automatic_timer = 0; /* if the list method is still running, stop it */ if ( list_timer ) gtk_timeout_remove( list_timer ); list_timer = 0; /* if the list method is still running, close the list file */ if ( list_file ) { fclose( list_file ); list_file = (FILE*)0; } /* stop gtk */ gtk_main_quit(); /* exit here */ gdk_exit( 0 ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "Quit" button request, or "destroy" signal request to quit */ static void control_Quit( GtkWidget* widget,GtkWidget* window ) { snowflake_message msg; /* tell the Generation process to quit? */ if ( g_ping == 0 ) { msg.cmd = cmd_QUIT; snd_msg( g_mp,&msg ); } /* tell the View process to quit? */ if ( v_ping == 0 ) { msg.cmd = cmd_QUIT; snd_msg( v_mp,&msg ); } control_Exit( FALSE,FALSE ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* a window manager request to quit */ static gint control_Close( GtkWidget* widget, GdkEvent* event, gpointer* data ) { return FALSE; /* the "destroy" signal handler control_Quit() * will be called */ } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* check that both children are still alive */ static gint ping_children( gpointer data ) { snowflake_message msg; if ( g_ping != 0 || v_ping != 0 ) { if ( g_ping != 0 && v_ping != 0 ) fprintf( stderr,"Control: no response from Generate and View\n" ); else if ( g_ping != 0 ) fprintf( stderr,"Control: no response from Generate\n" ); else if ( v_ping != 0 ) fprintf( stderr,"Control: no response from View\n" ); control_Exit( TRUE,TRUE ); } /* don't ping Generation if it's generating */ if ( state != state_Generating ) { msg.cmd = cmd_PING; if ( !snd_msg( g_mp,&msg ) ) { fprintf( stderr,"Control: unable to send PING command to Generate\n" ); control_Exit( FALSE,TRUE ); } g_ping++; } /* don't ping View if it's viewing */ if ( state != state_Viewing ) { msg.cmd = cmd_PING; if ( !snd_msg( v_mp,&msg ) ) { fprintf( stderr,"Control: unable to send PING command to View\n" ); control_Exit( TRUE,FALSE ); } v_ping++; } return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static gint press_button( gpointer data ) { method_e command_method = (method_e)data; switch ( command_method ) { case method_Named : gtk_button_clicked( GTK_BUTTON( named_Draw_button ) ); break; case method_Automatic : gtk_button_clicked( GTK_BUTTON( automatic_Run_button ) ); break; case method_List : gtk_button_clicked( GTK_BUTTON( list_Run_button ) ); break; } gtk_timeout_remove( button_timer ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void generate( gchar* key, gint size, gint symmetry, gint edges, gint colour_scheme, gint banding, gint centre ) { snowflake_message msg; strcpy( gen_key,key ); gen_size = get_image_size( size ); if ( state != state_Specifying ) { #ifdef QUIT_ON_OVERRUN fprintf( stderr,"Control: not ready to generate\n" ); control_Exit( TRUE,TRUE ); #else /* generation in progress, try again in a bit */ return; #endif } state = state_Generating; /* tell Generate to generate */ msg.cmd = cmd_GENERATE; sprintf( msg.data.s,GENERATE_CMD_FORMAT, key,size,symmetry,edges,colour_scheme,banding,centre ); if ( !snd_msg( g_mp,&msg ) ) { fprintf( stderr,"Control: unable to send GENERATE command\n" ); control_Exit( TRUE,TRUE ); } generations++; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* receive input from Generation process */ static void g_input_Callback( gpointer clientdata, gint source, GdkInputCondition condition ) { snowflake_message msg; if ( !rcv_msg( g_mp,&msg ) ) { fprintf( stderr,"Control: incomplete message from Generate\n" ); control_Exit( TRUE,TRUE ); } switch ( msg.cmd ) { case cmd_CLOSE : /* Generate has asked to quit */ control_Exit( TRUE,TRUE ); break; case cmd_QUIT : /* Generate has quit */ control_Exit( FALSE,TRUE ); break; case cmd_PING : /* Generate has pinged us */ msg.cmd = cmd_PONG; if ( !snd_msg( g_mp,&msg ) ) { fprintf( stderr, "Control: unable to send PING command to Generate\n" ); control_Exit( FALSE,TRUE ); } break; case cmd_PONG : /* respond to a Generate pong (ping ack) */ g_ping--; generation_pid = msg.data.i; break; case cmd_ACK : /* Generate has acknowledged last generation */ if ( state != state_Generating ) { fprintf( stderr,"Control: not ready to view\n" ); control_Exit( TRUE,TRUE ); } state = state_Viewing; /* tell View to view */ msg.cmd = cmd_VIEW; sprintf( msg.data.s,VIEW_CMD_FORMAT, gen_key,gen_size,gen_size ); if ( !snd_msg( v_mp,&msg ) ) { fprintf( stderr,"Control: unable to send VIEW command\n" ); control_Exit( FALSE,TRUE ); } /* enable the buttons the first time around */ if ( generations == 1 && gen_state != gen_state_Running ) { gtk_widget_set_sensitive( Save_Image_button,TRUE ); } break; case cmd_TIMEOUT : /* only for the Generate or View processes */ break; case cmd_GENERATE : /* only for the Generate process */ break; case cmd_VIEW : /* only for the View process */ break; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* receive input from View process */ static void v_input_Callback( gpointer clientdata, gint source, GdkInputCondition condition ) { snowflake_message msg; if ( !rcv_msg( v_mp,&msg ) ) { fprintf( stderr,"Control: incomplete message from View\n" ); control_Exit( TRUE,TRUE ); } switch ( msg.cmd ) { case cmd_CLOSE : /* View has asked to quit */ control_Exit( TRUE,TRUE ); break; case cmd_QUIT : /* View has quit */ control_Exit( TRUE,FALSE ); break; case cmd_PING : /* View has pinged us */ msg.cmd = cmd_PONG; if ( !snd_msg( v_mp,&msg ) ) { fprintf( stderr, "Control: unable to send PING command to View\n" ); control_Exit( TRUE,FALSE ); } break; case cmd_PONG : /* respond to a View pong (ping ack) */ v_ping--; view_pid = msg.data.i; break; case cmd_ACK : /* View has acknowledged last view */ if ( state != state_Viewing ) { fprintf( stderr,"Control: not ready to specify\n" ); control_Exit( TRUE,TRUE ); } /* we are now ready to start again */ state = state_Specifying; break; case cmd_TIMEOUT : /* only for the Generate or View processes */ break; case cmd_GENERATE : /* only for the Generate process */ break; case cmd_VIEW : /* only for the View process */ break; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* filter a key for hexadecimal digits */ static gint filter_key( gchar* old_key,gchar* new_key ) { gchar* op = old_key; gchar* np = new_key; gchar ch; gint digits = 0; while ( ( ch = *op ) != '\0' ) { if ( isxdigit( ch ) ) { ch = toupper( ch ); *np++ = ch; digits++; } op++; } *np = '\0'; return digits; } /* filter an automatic generation specification * ? : set the key to a new random value of the same length * +m : add a fixed value to the key * -n : subtract a fixed value to the key * -n .. +m : add a random value to the key */ static gint filter_generation( gchar* generation, gchar* step,gchar* lo,gchar* hi ) { gchar* gp = generation; gchar ch; gchar* dp; gint numbers; gint digits; numbers = 0; digits = 0; dp = step; step[0] = '\0'; lo[0] = '\0'; hi[0] = '\0'; while ( ( ch = *gp ) ) { if ( ch == '?' && numbers == 0 ) { *dp++ = ch; *dp = '\0'; return 1; } else if ( ( ch == '+' || ch == '-' || ch == '<' || ch == '>' ) && digits == 0 ) *dp++ = ch; else if ( isxdigit( ch ) ) { ch = toupper( ch ); *dp++ = ch; digits++; } else if ( ch == '.' && numbers == 0 ) { numbers = 1; digits = 0; *dp = '\0'; strcpy( lo,step ); step[0] = '\0'; dp = hi; } gp++; } *dp = '\0'; if ( *step ) return 1; if ( *lo && *hi ) return 2; return 0; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* generate a random hexadecimal string of specified length */ static void set_random_key( gchar* step_text,gint digits ) { gint i; gint len; gchar format[8]; gint lim; len = 2*sizeof( int ); sprintf( format,"%%%02dX",len ); lim = ( digits / len ) + ( ( digits % len ) != 0 ); for ( i = 0; i < lim; i++ ) sprintf( &step_text[len*i],format,random() ); step_text[digits] = '\0'; } /* generate a random hexadecimal string in a specified range */ static void set_random_range( gchar* step_text, gchar* lo_text,gchar* hi_text,gint digits ) { gchar range_text[MAX_KEY+1]; gchar notlo_text[MAX_KEY+1]; gint range; gint lo; gint hi; gint random_number; strcpy( range_text,hi_text ); /* range = hi + !lo + 1 */ twos_complement( notlo_text,lo_text ); add_to_xstring( range_text,notlo_text ); add_to_xstring( range_text,"1" ); lo = xtoi( lo_text ); hi = xtoi( hi_text ); range = abs( xtoi( range_text ) ); random_number = ( random() % range ) + lo; sprintf( step_text,"%X",random_number ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static char* hex_ch = "0123456789ABCDEF"; #define HEX( ch ) ( (int)( strchr( hex_ch,(int)ch ) - hex_ch ) ) #define INVHEX( ch ) ( 15 - (int)( strchr( hex_ch,(int)ch ) - hex_ch ) ) /* convert a optionally signed hexadecimal number to an integer */ static gint xtoi( gchar* number_text ) { gchar* np; gint i; gint sign = +1; gint number = 0; np = number_text; if ( *np == '-' ) { np++; sign = -1; } else if ( *np == '+' ) { np++; sign = +1; } for ( i = 0; i < 2*sizeof( int ),*np; i++,np++ ) { number = number * 16 + HEX( *np ); } if ( ( number < 0 ) && ( sign < 0 ) ) return number; return sign * number; } /* calculate the two's compliment of * an optionally signed hexadecimal number, * the number can be at most MAX_KEY digits long */ static void twos_complement( gchar* not_number_text,gchar* number_text ) { gchar tmp_number_text[MAX_KEY+1]; gint digits; gchar* np; np = number_text; if ( *np == '-' ) { np++; strcpy( not_number_text,np ); return; } else if ( *np == '+' ) np++; strcpy( not_number_text,np ); np = not_number_text; digits = strlen( np ); while ( *np ) { *np = hex_ch[ INVHEX( *np ) ]; np++; } *np = '\0'; strcpy( tmp_number_text,not_number_text ); add_to_xstring( tmp_number_text,"1" ); strcpy( not_number_text,tmp_number_text ); } /* add one hexadecimal to another */ static void add_to_xstring( gchar* sum_text,gchar* number_text ) { gchar inter_text[MAX_KEY+1]; gchar tmp_number_text[MAX_KEY+1]; gchar not_number_text[MAX_KEY+1]; gint digits; gint n_digits; gchar* sp; gchar* np; gint carry; gint i; gint x; sp = sum_text; if ( *sp == '-' || *sp == '+' ) sp++; digits = strlen( sp ); np = number_text; memset( inter_text,'0',digits ); inter_text[digits] = '\0'; if ( *np == '-' ) { np++; n_digits = strlen( np ); strncpy( &inter_text[digits - n_digits],np,n_digits ); twos_complement( tmp_number_text,inter_text ); } else { if ( *np == '+' ) np++; n_digits = strlen( np ); memcpy( &inter_text[digits - n_digits],np,n_digits ); strcpy( tmp_number_text,inter_text ); } np = tmp_number_text; carry = 0; for ( i = digits-1; i >= 0; i-- ) { x = HEX( sp[i] ) + HEX( np[i] ) + carry; carry = x / 16; x = x % 16; sp[i] = hex_ch[x]; } } static void shift_xstring( gchar* new_key_text,gchar* shift_text ) { gchar bits[2*4*MAX_KEY+1]; int i; gchar ch; gchar* digit; int shift; int len; int key_bits; len = strlen( new_key_text ); key_bits = 4 * len; shift = xtoi( &shift_text[1] ); if ( shift < 1 || shift > key_bits-1 ) return; digit = new_key_text; for ( i = 0; i < key_bits; i++ ) { if ( i % 4 == 0 ) ch = HEX( *digit++ ); bits[i] = ( ( ch & ( 8 >> ( i & 3 ) ) ) != 0 ? 1 : 0 ); } memcpy( &bits[key_bits],&bits[0],key_bits ); if ( *shift_text == '>' ) shift = key_bits - shift; digit = new_key_text; digit--; for ( i = 0; i < key_bits; i++ ) { if ( i % 4 == 0 ) *++digit = '\0'; *digit |= ( bits[i+shift] << ( 3 - ( i & 3 ) ) ); } for ( i = 0; i < len; i++ ) { new_key_text[i] = hex_ch[ new_key_text[i] ]; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* enable/disable the Settings menus/buttons */ static void set_Settings_Sensitive( gint sensitive ) { gtk_widget_set_sensitive( size_option_menu,sensitive ); gtk_widget_set_sensitive( symmetry_option_menu,sensitive ); gtk_widget_set_sensitive( edges_option_menu,sensitive ); gtk_widget_set_sensitive( colour_option_menu,sensitive ); gtk_widget_set_sensitive( banding_spin, sensitive ); gtk_widget_set_sensitive( centre_spin, sensitive ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* choose a size */ static void size_Select_Callback( GtkWidget* widget,gpointer data ) { size = (int)data; switch ( size ) { case size_032x032 : break; case size_064x064 : break; case size_128x128 : break; case size_256x256 : break; case size_512x512 : break; } } /* choose the symmetry */ static void symmetry_Select_Callback( GtkWidget* widget,gpointer data ) { symmetry = (int)data; switch ( symmetry ) { case symmetry_VERTICAL : break; case symmetry_HORIZONTAL : break; } } /* display edges? */ static void edges_Select_Callback( GtkWidget* widget,gpointer data ) { edges = (int)data; switch ( edges ) { case edges_NO : break; case edges_GRAY : break; case edges_GRAY_SOLID : break; case edges_YES : break; } } /* choose a colour scheme */ static void colour_scheme_Select_Callback( GtkWidget* widget,gpointer data ) { colour_scheme = (int)data; switch ( colour_scheme ) { case colour_scheme_WHITE_ON_BLACK : break; case colour_scheme_BLACK_ON_WHITE : break; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* switch note book pages */ static void method_Switch( GtkWidget* widget, GtkNotebookPage* page,gint page_num ) { GtkNotebookPage* oldpage; oldpage = GTK_NOTEBOOK( widget )->cur_page; method = page_num; if ( page == oldpage ) return; if ( !list_timer && Save_Design_button && Add_Design_button ) { if ( page_num == method_List ) { gtk_widget_set_sensitive( Save_Design_button,FALSE ); if ( design_line >= 0 ) gtk_widget_set_sensitive( Add_Design_button,FALSE ); } else { gtk_widget_set_sensitive( Save_Design_button,TRUE ); if ( design_line >= 0 ) gtk_widget_set_sensitive( Add_Design_button,TRUE ); } } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* named "Enter" key in 'name' entry */ static void named_Enter_Callback( GtkWidget* widget,GtkWidget* entry ) { gchar new_key_text[MAX_KEY+1]; gchar* name_text; name_text = gtk_entry_get_text( GTK_ENTRY( entry ) ); if ( name_text && *name_text ) { hash_key( new_key_text,name_text ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* named "Draw" button */ static void named_Draw_Callback( GtkWidget* widget,GtkWidget* window ) { gchar new_key_text[MAX_KEY+1]; gchar* name_text; name_text = gtk_entry_get_text( GTK_ENTRY( named_Name ) ); if ( name_text && *name_text ) { hash_key( new_key_text,name_text ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* named "Permute" button */ static void named_Permute_Callback( GtkWidget* widget,GtkWidget* window ) { gchar new_name_text[MAX_NAME+1]; gchar* name_text; gchar new_key_text[MAX_KEY+1]; int pos; gchar ch; name_text = gtk_entry_get_text( GTK_ENTRY( named_Name ) ); if ( name_text && *name_text ) { strcpy( new_name_text,name_text ); if ( strlen( new_name_text ) >= 2 ) { pos = ( random() % ( strlen( new_name_text ) - 1 ) ) + 1; ch = new_name_text[0]; new_name_text[0] = new_name_text[pos]; new_name_text[pos] = ch; } gtk_entry_set_text( GTK_ENTRY( named_Name ),new_name_text ); hash_key( new_key_text,name_text ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* named "Make Key" button */ static void named_Make_Key_Callback( GtkWidget* widget,GtkWidget* window ) { gchar* name_text; gchar new_key_text[MAX_KEY+1]; name_text = gtk_entry_get_text( GTK_ENTRY( named_Name ) ); if ( name_text && *name_text ) { hash_key( new_key_text,name_text ); gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); } } /* convert a name into a hexadecimal key */ static void hash_key( gchar* key,gchar* name ) { gint chars; gint i; chars = strlen( name ); for ( i = 0; i < chars; i++ ) sprintf( &key[2*i],"%02X",name[i] ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* automatic "Enter" key in 'key' entry */ static void automatic_Enter_Callback( GtkWidget* widget,GtkWidget* entry ) { gchar old_key_text[MAX_KEY+1]; gchar new_key_text[MAX_KEY+1]; gint digits; strcpy( old_key_text,gtk_entry_get_text( GTK_ENTRY( entry ) ) ); if ( *old_key_text ) { digits = filter_key( old_key_text,new_key_text ); if ( digits == 0 ) { new_key_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); return; } gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* automatic "Draw" button */ static void automatic_Draw_Callback( GtkWidget* widget,GtkWidget* window ) { gchar old_key_text[MAX_KEY+1]; gchar new_key_text[MAX_KEY+1]; gint digits; strcpy( old_key_text,gtk_entry_get_text( GTK_ENTRY( automatic_Key ) ) ); if ( *old_key_text ) { digits = filter_key( old_key_text,new_key_text ); if ( digits == 0 ) { new_key_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); return; } gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* automatic "Next" button */ static void automatic_Next_Callback( GtkWidget* widget,GtkWidget* window ) { automatic_Next_one(); } /* automatic "Run" button */ static void automatic_Run_Callback( GtkWidget* widget,GtkWidget* window ) { gchar old_generation_text[MAX_GENERATION+1]; gchar old_key_text[MAX_KEY+1]; gchar new_key_text[MAX_KEY+1]; gchar step_text[MAX_KEY+1]; gchar lo_text[MAX_KEY+1]; gchar hi_text[MAX_KEY+1]; gchar* speed_text; gint digits; gint numbers; gint interval; strcpy( old_key_text, gtk_entry_get_text( GTK_ENTRY( automatic_Key ) ) ); strcpy( old_generation_text, gtk_entry_get_text( GTK_ENTRY( automatic_Generation ) ) ); if ( *old_key_text && *old_generation_text ) { digits = filter_key( old_key_text,new_key_text ); numbers = filter_generation( old_generation_text, step_text,lo_text,hi_text ); if ( digits == 0 || numbers == 0 ) return; } else return; set_Settings_Sensitive( FALSE ); gtk_widget_set_sensitive( named_page, FALSE ); gtk_widget_set_sensitive( list_page, FALSE ); gtk_widget_set_sensitive( automatic_Key, FALSE ); gtk_widget_set_sensitive( automatic_Generation, FALSE ); gtk_widget_set_sensitive( automatic_Speed, FALSE ); gtk_widget_set_sensitive( automatic_Draw_button,FALSE ); gtk_widget_set_sensitive( automatic_Next_button,FALSE ); gtk_widget_set_sensitive( automatic_Run_button, FALSE ); gtk_widget_set_sensitive( automatic_Stop_button,TRUE ); gtk_widget_set_sensitive( Save_Image_button, FALSE ); gtk_widget_set_sensitive( Save_Design_button, FALSE ); if ( design_line >= 0 ) gtk_widget_set_sensitive( Add_Design_button, FALSE ); gtk_widget_set_sensitive( About_button, FALSE ); gen_state = gen_state_Running; speed_text = gtk_entry_get_text( GTK_ENTRY( automatic_Speed ) ); interval = ( 60 * 1000 ) / atoi( speed_text ); automatic_count = 1; automatic_Next_one(); automatic_timer = gtk_timeout_add( interval,automatic_timeout,window ); } /* automatic "Stop" button */ static void automatic_Stop_Callback( GtkWidget* widget,GtkWidget* window ) { gen_state = gen_state_Stopped; gtk_timeout_remove( automatic_timer ); automatic_timer = 0; gtk_widget_set_sensitive( About_button, TRUE ); gtk_widget_set_sensitive( Save_Design_button, TRUE ); if ( design_line >= 0 ) gtk_widget_set_sensitive( Add_Design_button, TRUE ); gtk_widget_set_sensitive( Save_Image_button, TRUE ); gtk_widget_set_sensitive( automatic_Stop_button,FALSE ); gtk_widget_set_sensitive( automatic_Run_button, TRUE ); gtk_widget_set_sensitive( automatic_Next_button,TRUE ); gtk_widget_set_sensitive( automatic_Draw_button,TRUE ); gtk_widget_set_sensitive( automatic_Speed, TRUE ); gtk_widget_set_sensitive( automatic_Generation, TRUE ); gtk_widget_set_sensitive( automatic_Key, TRUE ); gtk_widget_set_sensitive( list_page, TRUE ); gtk_widget_set_sensitive( named_page, TRUE ); set_Settings_Sensitive( TRUE ); } /* automatic 'Next' operation */ static void automatic_Next_one( void ) { gchar old_generation_text[MAX_GENERATION+1]; gchar new_generation_text[MAX_GENERATION+1]; gchar old_key_text[MAX_KEY+1]; gchar new_key_text[MAX_KEY+1]; gchar step_text[MAX_KEY+1]; gchar lo_text[MAX_KEY+1]; gchar hi_text[MAX_KEY+1]; gint numbers; gint digits; strcpy( old_generation_text, gtk_entry_get_text( GTK_ENTRY( automatic_Generation ) ) ); strcpy( old_key_text, gtk_entry_get_text( GTK_ENTRY( automatic_Key ) ) ); if ( *old_key_text ) { digits = filter_key( old_key_text,new_key_text ); if ( digits == 0 ) { new_key_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); } numbers = filter_generation( old_generation_text, step_text,lo_text,hi_text ); if ( numbers == 0 ) { new_generation_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Generation ), new_generation_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Generation ),-1 ); } if ( digits == 0 || numbers == 0 ) return; if ( numbers == 1 ) { if ( *step_text == '?' ) { strcpy( new_generation_text,step_text ); set_random_key( step_text,strlen( new_key_text ) ); strcpy( new_key_text,step_text ); } else if ( *step_text == '>' || *step_text == '<' ) { strcpy( new_generation_text,step_text ); shift_xstring( new_key_text,step_text ); } else { strcpy( new_generation_text,step_text ); add_to_xstring( new_key_text,step_text ); } } else if ( numbers == 2 ) { if ( xtoi( lo_text ) > xtoi( hi_text ) ) { strcpy( step_text,lo_text ); strcpy( lo_text,hi_text ); strcpy( hi_text,step_text ); } sprintf( new_generation_text,"%s .. %s",lo_text,hi_text ); set_random_range( step_text,lo_text,hi_text,strlen( new_key_text ) ); add_to_xstring( new_key_text,step_text ); } gtk_entry_set_text( GTK_ENTRY( automatic_Key ),new_key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); gtk_entry_set_text( GTK_ENTRY( automatic_Generation ), new_generation_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Generation ),-1 ); banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); generate( new_key_text,size,symmetry,edges,colour_scheme,banding,centre ); } } /* next "Run" generation */ static gint automatic_timeout( gpointer data ) { automatic_count++; automatic_Next_one(); return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* loop over design list? */ static void loop_Select_Callback( GtkWidget* widget,gpointer data ) { loop = (int)data; switch ( loop ) { case loop_ONCE : break; case loop_REPEAT : break; } } /* list "Open" button */ static void list_Open_Callback( GtkWidget* widget,GtkWidget* parent ) { static GtkWidget* window = NULL; GtkWidget* button; if ( !window ) { window = gtk_file_selection_new( "Open Design" ); strcpy( list_filespec,gtk_entry_get_text( GTK_ENTRY( list_Filespec ) ) ); gtk_file_selection_set_filename( GTK_FILE_SELECTION( window ), list_filespec ); gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( window ) ); gtk_window_position( GTK_WINDOW( window ),GTK_WIN_POS_MOUSE ); gtk_signal_connect( GTK_OBJECT( window ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroyed ), &window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->ok_button ), "clicked", GTK_SIGNAL_FUNC( open_design_file_chosen ), window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->cancel_button ), "clicked", GTK_SIGNAL_FUNC( open_design_file_choice_cancelled ), window ); button = gtk_button_new_with_label( "Hide File Ops" ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)hide_selection_fileops, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); button = gtk_button_new_with_label( "Show File Ops" ); gtk_signal_connect_object( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)gtk_file_selection_show_fileop_buttons, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); } if ( !GTK_WIDGET_VISIBLE( window ) ) { gtk_widget_show( window ); gtk_widget_set_sensitive( snowflake_window,FALSE ); gtk_grab_add( window ); } else { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( window ); gtk_widget_destroy( window ); } } /* list "Open" dialog 'Ok' */ static void open_design_file_chosen( GtkWidget* w,GtkFileSelection* fs ) { static gchar current_dir[512]; strcpy( list_filespec, gtk_file_selection_get_filename( GTK_FILE_SELECTION( fs ) ) ); if ( !*list_filespec || ( list_filespec[strlen( list_filespec )-1] == '/' ) ) *list_filespec = '\0'; if ( getcwd( current_dir,512 ) && strncmp( current_dir,list_filespec,strlen( current_dir ) ) == 0 ) gtk_entry_set_text( GTK_ENTRY( list_Filespec ), &list_filespec[strlen(current_dir)+1] ); else gtk_entry_set_text( GTK_ENTRY( list_Filespec ), list_filespec ); gtk_entry_set_position( GTK_ENTRY( list_Filespec ),-1 ); gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); } /* list "Open" dialog 'Cancel' */ static void open_design_file_choice_cancelled( GtkWidget* w, GtkFileSelection* fs ) { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); } /* list "Run" button */ static void list_Run_Callback( GtkWidget* widget,GtkWidget* window ) { gchar* speed_text; gint interval; strcpy( list_filespec,gtk_entry_get_text( GTK_ENTRY( list_Filespec ) ) ); if ( !*list_filespec ) return; set_Settings_Sensitive( FALSE ); gtk_widget_set_sensitive( named_page, FALSE ); gtk_widget_set_sensitive( automatic_page, FALSE ); gtk_widget_set_sensitive( list_Filespec, FALSE ); gtk_widget_set_sensitive( list_Speed, FALSE ); gtk_widget_set_sensitive( list_option_Loop, FALSE ); gtk_widget_set_sensitive( list_Open_button, FALSE ); gtk_widget_set_sensitive( list_Run_button, FALSE ); gtk_widget_set_sensitive( list_Stop_button, TRUE ); gtk_widget_set_sensitive( Save_Image_button, FALSE ); gtk_widget_set_sensitive( About_button, FALSE ); speed_text = gtk_entry_get_text( GTK_ENTRY( list_Speed ) ); interval = ( 60 * 1000 ) / atoi( speed_text ); strcpy( list_filespec,gtk_entry_get_text( GTK_ENTRY( list_Filespec ) ) ); list_file = fopen( list_filespec,"r" ); if ( !list_file ) { sprintf( error_message,"unable to open '%s'\n %d : %s\n", design_filespec,errno,strerror( errno ) ); error_Dialog( error_message ); return; } gen_state = gen_state_Running; list_count = 1; list_line = 0; if ( !list_read_one() ) { gen_state = gen_state_Stopped; return; } list_timer = gtk_timeout_add( interval,list_timeout,window ); } /* list "Stop" button */ static void list_Stop_Callback( GtkWidget* widget,GtkWidget* window ) { gen_state = gen_state_Stopped; gtk_timeout_remove( list_timer ); list_timer = 0; gtk_widget_set_sensitive( About_button, TRUE ); gtk_widget_set_sensitive( Save_Image_button, TRUE ); gtk_widget_set_sensitive( list_Stop_button, FALSE ); gtk_widget_set_sensitive( list_Run_button, TRUE ); gtk_widget_set_sensitive( list_Open_button, TRUE ); gtk_widget_set_sensitive( list_option_Loop, TRUE ); gtk_widget_set_sensitive( list_Speed, TRUE ); gtk_widget_set_sensitive( list_Filespec, TRUE ); gtk_widget_set_sensitive( automatic_page, TRUE ); gtk_widget_set_sensitive( named_page, TRUE ); set_Settings_Sensitive( TRUE ); } /* read one list file design */ static gint list_read_one( void ) { gchar local_key[MAX_KEY+1]; gint local_size; gint local_symmetry; gint local_edges; gint local_colour_scheme; gint local_banding; gint local_centre; gchar eol[8]; gint tally = 0; gint items; list_line++; read_first_line: if ( ( items = fscanf( list_file,GENERATE_SCAN_FORMAT_NL, local_key, &local_size, &local_symmetry, &local_edges, &local_colour_scheme, &local_banding, &local_centre, eol ) ) != 8 ) { if ( !loop ) { rewind( list_file ); return 0; } if ( tally == 0 ) { rewind( list_file ); tally++; list_line = 1; goto read_first_line; } else return 0; } generate( local_key, local_size, local_symmetry, local_edges, local_colour_scheme, local_banding, local_centre ); return 1; } /* generate next list generation */ static gint list_timeout( gpointer data ) { list_count++; if ( !list_read_one() ) { list_Stop_Callback( (GtkWidget*)0,(GtkWidget*)0 ); fclose( list_file ); list_file = (FILE*)0; } return TRUE; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "Save Image" button */ static void control_Save_Image( GtkWidget* widget,GtkWidget* parent ) { static GtkWidget* window = NULL; GtkWidget* button; if ( !window ) { window = gtk_file_selection_new( "Save Image as XPM" ); gtk_file_selection_set_filename( GTK_FILE_SELECTION( window ), xpm_filespec ); gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( window ) ); gtk_window_position( GTK_WINDOW( window ),GTK_WIN_POS_MOUSE ); gtk_signal_connect( GTK_OBJECT( window ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroyed ), &window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->ok_button ), "clicked", GTK_SIGNAL_FUNC( image_file_chosen ), window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->cancel_button ), "clicked", GTK_SIGNAL_FUNC( image_file_choice_cancelled ), window ); button = gtk_button_new_with_label( "Hide File Ops" ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)hide_selection_fileops, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); button = gtk_button_new_with_label( "Show File Ops" ); gtk_signal_connect_object( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)gtk_file_selection_show_fileop_buttons, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); } if ( !GTK_WIDGET_VISIBLE( window ) ) { gtk_widget_show( window ); gtk_widget_set_sensitive( snowflake_window,FALSE ); gtk_grab_add( window ); } else { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( window ); gtk_widget_destroy( window ); } } /* "Save Image" dialog 'Ok' */ static void image_file_chosen( GtkWidget* w,GtkFileSelection* fs ) { gchar key_text[MAX_KEY+1]; gchar* name_text; gchar* old_key_text; gint digits; int err_code; switch ( method ) { case method_Named : name_text = gtk_entry_get_text( GTK_ENTRY( named_Name ) ); if ( !name_text || !*name_text ) return; hash_key( key_text,name_text ); break; case method_Automatic : old_key_text = gtk_entry_get_text( GTK_ENTRY( automatic_Key ) ); if ( !old_key_text || !*old_key_text ) return; if ( filter_key( old_key_text,key_text ) == 0 ) { key_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Key ),key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); return; } gtk_entry_set_text( GTK_ENTRY( automatic_Key ),key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); break; case method_List : return; } strcpy( xpm_filespec, gtk_file_selection_get_filename( GTK_FILE_SELECTION( fs ) ) ); gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); if ( ( err_code = write_image_to_file( img_image,xpm_filespec,key_text ) ) != 0 ) { sprintf( error_message,"unable to save '%s'\n %d : %s\n", xpm_filespec,err_code,strerror( err_code ) ); error_Dialog( error_message ); } } /* "Save Image" dialog 'Cancel' */ static void image_file_choice_cancelled( GtkWidget* w,GtkFileSelection* fs ) { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* hide the File Operations in a file selector window */ static void hide_selection_fileops( GtkWidget* widget,GtkFileSelection* fs ) { gtk_file_selection_hide_fileop_buttons( fs ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "Save Design" button */ static void control_Save_Design( GtkWidget* widget,GtkWidget* parent ) { static GtkWidget* window = NULL; GtkWidget* button; if ( !window ) { window = gtk_file_selection_new( "Save Design" ); gtk_file_selection_set_filename( GTK_FILE_SELECTION( window ), design_filespec ); gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( window ) ); gtk_window_position( GTK_WINDOW( window ),GTK_WIN_POS_MOUSE ); gtk_signal_connect( GTK_OBJECT( window ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroyed ), &window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->ok_button ), "clicked", GTK_SIGNAL_FUNC( design_file_chosen ), window ); gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( window ) ->cancel_button ), "clicked", GTK_SIGNAL_FUNC( design_file_choice_cancelled ), window ); button = gtk_button_new_with_label( "Hide File Ops" ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)hide_selection_fileops, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); button = gtk_button_new_with_label( "Show File Ops" ); gtk_signal_connect_object( GTK_OBJECT( button ), "clicked", (GtkSignalFunc)gtk_file_selection_show_fileop_buttons, (gpointer)window ); gtk_box_pack_start( GTK_BOX( GTK_FILE_SELECTION( window )->action_area ), button,FALSE,FALSE,0 ); gtk_widget_show( button ); } if ( !GTK_WIDGET_VISIBLE( window ) ) { gtk_widget_show( window ); gtk_widget_set_sensitive( snowflake_window,FALSE ); gtk_grab_add( window ); } else { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( window ); gtk_widget_destroy( window ); } } /* "Save Design" dialog 'Ok' */ static void design_file_chosen( GtkWidget* w,GtkFileSelection* fs ) { strcpy( design_filespec, gtk_file_selection_get_filename( GTK_FILE_SELECTION( fs ) ) ); if ( *design_filespec && ( design_filespec[strlen( design_filespec )-1] != '/' ) ) { design_line = 0; gtk_widget_set_sensitive( Add_Design_button,TRUE ); } else { *design_filespec = '\0'; design_line = -1; gtk_widget_set_sensitive( Add_Design_button,FALSE ); } gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); } /* "Save Design" dialog 'Ok' */ static void design_file_choice_cancelled( GtkWidget* w,GtkFileSelection* fs ) { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( GTK_WIDGET( fs ) ); gtk_widget_destroy( GTK_WIDGET( fs ) ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "Add Design" button */ static void control_Add_Design( GtkWidget* widget,GtkWidget* window ) { gchar key_text[MAX_KEY+1]; gchar* name_text; gchar* old_key_text; gint digits; switch ( method ) { case method_Named : name_text = gtk_entry_get_text( GTK_ENTRY( named_Name ) ); if ( !name_text || !*name_text ) return; hash_key( key_text,name_text ); break; case method_Automatic : old_key_text = gtk_entry_get_text( GTK_ENTRY( automatic_Key ) ); if ( !old_key_text || !*old_key_text ) return; if ( filter_key( old_key_text,key_text ) == 0 ) { key_text[0] = '\0'; gtk_entry_set_text( GTK_ENTRY( automatic_Key ),key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); return; } gtk_entry_set_text( GTK_ENTRY( automatic_Key ),key_text ); gtk_entry_set_position( GTK_ENTRY( automatic_Key ),-1 ); break; case method_List : return; } design_file = fopen( design_filespec,"a+" ); if ( !design_file ) { sprintf( error_message,"unable to open '%s'\n %d : %s\n", design_filespec,errno,strerror( errno ) ); error_Dialog( error_message ); return; } banding = atoi( gtk_entry_get_text( GTK_ENTRY( banding_spin ) ) ); centre = atoi( gtk_entry_get_text( GTK_ENTRY( centre_spin ) ) ); fprintf( design_file,GENERATE_CMD_FORMAT, key_text,size,symmetry,edges,colour_scheme,banding,centre ); fprintf( design_file,"\n" ); fclose( design_file ); design_file = (FILE*)0; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* "About" button */ static void control_About( GtkWidget* widget,GtkWidget* window ) { GtkWidget* label; GtkWidget* button; static gchar about_Text[512]; About_dialog = gtk_dialog_new(); gtk_signal_connect( GTK_OBJECT( About_dialog ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroyed ), &About_dialog ); gtk_window_set_title( GTK_WINDOW( About_dialog ),"About snowflake"); gtk_container_border_width( GTK_CONTAINER( About_dialog ),BORDER ); sprintf( about_Text,"Snowflake\nversion 0.01a\n\n%s at %s\n%s\n%s", __DATE__,__TIME__,author,company ); label = gtk_label_new( about_Text ); gtk_misc_set_padding( GTK_MISC( label ),BORDER,BORDER ); gtk_box_pack_start( GTK_BOX( GTK_DIALOG( About_dialog )->vbox ), label,TRUE,TRUE,0 ); gtk_widget_show( label ); button = gtk_button_new_with_label( "OK" ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( About_OK_Callback ), NULL ); GTK_WIDGET_SET_FLAGS( button,GTK_CAN_DEFAULT ); gtk_box_pack_start( GTK_BOX( GTK_DIALOG( About_dialog )->action_area ), button,TRUE,TRUE,0 ); gtk_widget_grab_default( button ); gtk_widget_show( button ); gtk_widget_show( About_dialog ); gtk_widget_set_sensitive( snowflake_window,FALSE ); gtk_grab_add( About_dialog ); } /* "About" dialog 'Ok' */ static void About_OK_Callback( GtkWidget* widget,GtkWidget* window ) { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( About_dialog ); gtk_widget_destroy( About_dialog ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static method_e apply_args( int argc,char* argv[] ) { int command = 0; int option_index = 0; int val; int i; gchar generation_text[MAX_GENERATION+1]; gchar key_text[MAX_KEY+1]; gchar step_text[MAX_KEY+1]; gchar lo_text[MAX_KEY+1]; gchar hi_text[MAX_KEY+1]; method_e command_method = method_NULL; opterr = 0; /* disable getopt() generated messages */ while ( command >= 0 ) { option_index = 0; command = getopt_long( argc, argv, short_options, long_options, &option_index ); if ( command == -1 ) break; if ( ( command != c_MINIMIZE && command != c_VIEW_GEOMETRY ) && ( !optarg || !*optarg ) ) { fprintf( stderr,"Control: option %s requires an argument\n", argv[optind-1] ); continue; } switch ( command ) { case c_CONTROL_GEOMETRY : { int x,y; if ( sscanf( optarg,"%d%d",&x,&y ) == 2 ) { gint width,height; gint w_x,w_y,w_width,w_height,w_depth; width = gdk_screen_width(); height = gdk_screen_height(); gdk_window_get_geometry( snowflake_window->window, &w_x,&w_y,&w_width,&w_height,&w_depth ); if ( x < 0 ) x = width - w_width + x; if ( y < 0 ) y = height - w_height + y; gtk_widget_set_uposition( snowflake_window,x,y ); } } break; case c_MINIMIZE : iconify_window( snowflake_window ); break; case c_SIZE : for ( i = 0; i < SIZES; i++ ) if ( strncasecmp( optarg,size_table[i].label,strlen( optarg ) ) == 0 ) { size = size_table[i].id; gtk_option_menu_set_history( GTK_OPTION_MENU( size_option_menu ),size ); break; } if ( i == SIZES ) fprintf( stderr,"Control: invalid size %s\n",optarg ); break; case c_SYMMETRY : for ( i = 0; i < SYMMETRIES; i++ ) if ( strncasecmp( optarg,symmetry_table[i].label,strlen( optarg ) ) == 0 ) { symmetry = symmetry_table[i].id; gtk_option_menu_set_history( GTK_OPTION_MENU( symmetry_option_menu ),symmetry ); break; } if ( i == SYMMETRIES ) fprintf( stderr,"Control: invalid symmetry %s\n",optarg ); break; case c_EDGES : for ( i = 0; i < EDGES; i++ ) if ( strncasecmp( optarg,edges_table[i].label,strlen( optarg ) ) == 0 ) { edges = edges_table[i].id; gtk_option_menu_set_history( GTK_OPTION_MENU( edges_option_menu ),edges ); break; } if ( i == EDGES ) fprintf( stderr,"Control: invalid edges %s\n",optarg ); break; case c_COLOUR_SCHEME : for ( i = 0; i < COLOUR_SCHEMES; i++ ) if ( strncasecmp( optarg,colour_scheme_table[i].label,strlen( optarg ) ) == 0 ) { colour_scheme = colour_scheme_table[i].id; gtk_option_menu_set_history( GTK_OPTION_MENU( colour_option_menu ),colour_scheme ); break; } if ( i == COLOUR_SCHEMES ) fprintf( stderr,"Control: invalid edges %s\n",optarg ); break; case c_BANDING : val = atoi( optarg ); if ( val >= MIN_BANDING && val <= MAX_BANDING ) { banding = val; gtk_spin_button_set_value( GTK_SPIN_BUTTON( banding_spin ),(gfloat)banding ); break; } fprintf( stderr,"Control: invalid banding %s\n",optarg ); break; case c_CENTRE : val = atoi( optarg ); if ( val >= MIN_CENTRE && val <= MAX_CENTRE ) { centre = val; gtk_spin_button_set_value( GTK_SPIN_BUTTON( centre_spin ),(gfloat)centre ); break; } fprintf( stderr,"Control: invalid centre %s\n",optarg ); break; case c_NAME : if ( strlen( optarg ) <= MAX_NAME ) { method = method_Named; command_method = method; gtk_notebook_set_page( GTK_NOTEBOOK( notebook ),method ); gtk_entry_set_text( GTK_ENTRY( named_Name ),optarg ); break; } fprintf( stderr,"Control: name '%s' too long\n",optarg ); break; case c_KEY : if ( strlen( optarg ) <= MAX_KEY ) { val = filter_key( optarg,key_text ); if ( val > 0 ) { method = method_Automatic; command_method = method; gtk_notebook_set_page( GTK_NOTEBOOK( notebook ),method ); gtk_entry_set_text( GTK_ENTRY( automatic_Key ),key_text ); break; } else { fprintf( stderr,"Control: invalid key '%s'\n",optarg ); break; } } fprintf( stderr,"Control: key '%s' too long\n",optarg ); break; case c_LIST : if ( strlen( optarg ) <= MAX_FILESPEC ) { method = method_List; command_method = method; gtk_notebook_set_page( GTK_NOTEBOOK( notebook ),method ); gtk_entry_set_text( GTK_ENTRY( list_Filespec ),optarg ); break; } fprintf( stderr,"Control: list '%s' too long\n",optarg ); break; case c_SPEED : val = atoi( optarg ); if ( val >= MIN_SPEED && val <= MAX_SPEED ) { gtk_spin_button_set_value( GTK_SPIN_BUTTON( automatic_Speed ),(gfloat)val ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( list_Speed ), (gfloat)val ); break; } fprintf( stderr,"Control: invalid centre %s\n",optarg ); break; case c_GENERATION : val = filter_generation( optarg,step_text,lo_text,hi_text ); if ( val > 0 ) { if ( val == 1 ) { strcpy( generation_text,step_text ); } else if ( val == 2 ) { if ( xtoi( lo_text ) > xtoi( hi_text ) ) { strcpy( step_text,lo_text ); strcpy( lo_text,hi_text ); strcpy( hi_text,step_text ); } sprintf( generation_text,"%s .. %s",lo_text,hi_text ); } gtk_entry_set_text( GTK_ENTRY( automatic_Generation ),generation_text ); break; } fprintf( stderr,"Control: invalid generation '%s'\n",optarg ); break; case c_LOOP : for ( i = 0; i < LOOPS; i++ ) if ( strncasecmp( optarg,loop_table[i].label,strlen( optarg ) ) == 0 ) { loop = loop_table[i].id; gtk_option_menu_set_history( GTK_OPTION_MENU( list_option_Loop ),loop ); break; } if ( i == LOOPS ) fprintf( stderr,"Control: invalid loop %s\n",optarg ); break; case '?' : break; default: /*fprintf( stderr,"getopt() returned code 0x%X ?\n",command );*/ break; } } return command_method; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* build the Control window interface */ static void build_Control_Window( void ) { GtkWidget* label; GtkWidget* window_box; GtkWidget* box; GtkWidget* box_group; GtkWidget* box_row; GtkWidget* table; GtkWidget* menu; GtkWidget* menu_item; GtkWidget* separator; GtkAdjustment* adjustment; gint i; /* main window */ snowflake_window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_signal_connect( GTK_OBJECT( snowflake_window ), "destroy", GTK_SIGNAL_FUNC( control_Quit ), &snowflake_window ); gtk_signal_connect( GTK_OBJECT( snowflake_window ), "delete_event", GTK_SIGNAL_FUNC( control_Close ), &snowflake_window ); gtk_window_set_title( GTK_WINDOW( snowflake_window ),"Snowflake" ); gtk_container_border_width( GTK_CONTAINER( snowflake_window ),0 ); /* main box */ window_box = gtk_vbox_new( FALSE,0 ); gtk_container_add( GTK_CONTAINER( snowflake_window ),window_box ); gtk_widget_show( window_box ); box_group = gtk_vbox_new( FALSE,BORDER ); gtk_container_border_width( GTK_CONTAINER( box_group ),BORDER ); gtk_box_pack_start( GTK_BOX( window_box ),box_group,FALSE,TRUE,0 ); gtk_widget_show( box_group ); /* settings table */ table = gtk_table_new( SETTINGS,2,FALSE ); gtk_box_pack_start( GTK_BOX( box_group ),table,FALSE,TRUE,0 ); /* build size option pulldown */ label = gtk_label_new( "size:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); size_option_menu = gtk_option_menu_new(); gtk_widget_show( size_option_menu ); size_menu = gtk_menu_new(); for ( i = 0; i < SIZES; i++ ) { menu_item = gtk_menu_item_new_with_label( size_table[i].label ); gtk_signal_connect( GTK_OBJECT( menu_item ), "activate", (GtkSignalFunc)size_Select_Callback, (gpointer)size_table[i].id ); gtk_menu_append( GTK_MENU( size_menu ),menu_item ); gtk_widget_show( menu_item ); } gtk_menu_set_active( GTK_MENU( size_menu ),size ); gtk_option_menu_set_menu( GTK_OPTION_MENU( size_option_menu ),size_menu ); gtk_table_attach( GTK_TABLE( table ),size_option_menu,1,2,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* build symmetry option pulldown */ label = gtk_label_new( "symmetry:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); symmetry_option_menu = gtk_option_menu_new(); gtk_widget_show( symmetry_option_menu ); symmetry_menu = gtk_menu_new(); for ( i = 0; i < SYMMETRIES; i++ ) { menu_item = gtk_menu_item_new_with_label( symmetry_table[i].label ); gtk_signal_connect( GTK_OBJECT( menu_item ), "activate", (GtkSignalFunc)symmetry_Select_Callback, (gpointer)symmetry_table[i].id ); gtk_menu_append( GTK_MENU( symmetry_menu ),menu_item ); gtk_widget_show( menu_item ); } gtk_menu_set_active( GTK_MENU( symmetry_menu ),symmetry ); gtk_option_menu_set_menu( GTK_OPTION_MENU( symmetry_option_menu ),symmetry_menu ); gtk_table_attach( GTK_TABLE( table ),symmetry_option_menu,1,2,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* build edges option pulldown */ label = gtk_label_new( "edges:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); edges_option_menu = gtk_option_menu_new(); gtk_widget_show( edges_option_menu ); edges_menu = gtk_menu_new(); for ( i = 0; i < EDGES; i++ ) { menu_item = gtk_menu_item_new_with_label( edges_table[i].label ); gtk_signal_connect( GTK_OBJECT( menu_item ), "activate", (GtkSignalFunc)edges_Select_Callback, (gpointer)edges_table[i].id ); gtk_menu_append( GTK_MENU( edges_menu ),menu_item ); gtk_widget_show( menu_item ); } gtk_menu_set_active( GTK_MENU( edges_menu ),edges ); gtk_option_menu_set_menu( GTK_OPTION_MENU( edges_option_menu ),edges_menu ); gtk_table_attach( GTK_TABLE( table ),edges_option_menu,1,2,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* build colour scheme option pulldown */ label = gtk_label_new( "colours:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,4,5, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); colour_option_menu = gtk_option_menu_new(); gtk_widget_show( colour_option_menu ); colour_menu = gtk_menu_new(); for ( i = 0; i < COLOUR_SCHEMES; i++ ) { menu_item = gtk_menu_item_new_with_label( colour_scheme_table[i].label ); gtk_signal_connect( GTK_OBJECT( menu_item ), "activate", (GtkSignalFunc)colour_scheme_Select_Callback, (gpointer)colour_scheme_table[i].id ); gtk_menu_append( GTK_MENU( colour_menu ),menu_item ); gtk_widget_show( menu_item ); } gtk_menu_set_active( GTK_MENU( colour_menu ),colour_scheme ); gtk_option_menu_set_menu( GTK_OPTION_MENU( colour_option_menu ),colour_menu ); gtk_table_attach( GTK_TABLE( table ),colour_option_menu,1,2,4,5, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* banding depth spinbutton */ label = gtk_label_new( "banding:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,5,6, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); adjustment = (GtkAdjustment*)gtk_adjustment_new( DEF_BANDING, MIN_BANDING, MAX_BANDING, BANDING_STEP, BANDING_PAGE, 0.0 ); banding_spin = gtk_spin_button_new( adjustment,0,0 ); gtk_widget_show( banding_spin ); gtk_table_attach( GTK_TABLE( table ),banding_spin,1,2,5,6, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* banding scale centre spinbutton */ label = gtk_label_new( "centre size:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,6,7, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( label ); adjustment = (GtkAdjustment*)gtk_adjustment_new( DEF_CENTRE, MIN_CENTRE, MAX_CENTRE, CENTRE_STEP, CENTRE_PAGE, 0.0 ); centre_spin = gtk_spin_button_new( adjustment,0,0 ); gtk_widget_show( centre_spin ); gtk_table_attach( GTK_TABLE( table ),centre_spin,1,2,6,7, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); /* show the settings table */ gtk_widget_show( table ); /* horizontal seperator */ separator = gtk_hseparator_new(); gtk_box_pack_start( GTK_BOX( window_box ),separator,FALSE,TRUE,0 ); gtk_widget_show( separator ); /* generation methods */ notebook = gtk_notebook_new(); gtk_signal_connect( GTK_OBJECT( notebook ), "switch_page", GTK_SIGNAL_FUNC( method_Switch ), NULL ); gtk_notebook_set_tab_pos( GTK_NOTEBOOK( notebook ),GTK_POS_TOP ); gtk_box_pack_start( GTK_BOX( window_box ),notebook,TRUE,TRUE,0 ); gtk_container_border_width( GTK_CONTAINER( notebook ),BORDER ); /* Named page */ named_page = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( named_page ),2 ); box = gtk_vbox_new( FALSE,0 ); gtk_container_border_width( GTK_CONTAINER( box ),BORDER ); gtk_container_add( GTK_CONTAINER( named_page ),box ); table = gtk_table_new( 3,2,FALSE ); gtk_box_pack_start( GTK_BOX( box ),table,FALSE,TRUE,0 ); label = gtk_label_new( "name:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); named_Name = gtk_entry_new_with_max_length( MAX_NAME ); gtk_signal_connect( GTK_OBJECT( named_Name ), "activate", GTK_SIGNAL_FUNC( named_Enter_Callback ), named_Name ); gtk_table_attach( GTK_TABLE( table ),named_Name,1,2,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); box_group = gtk_hbox_new( FALSE,BORDER ); gtk_container_border_width( GTK_CONTAINER( box_group ),BORDER ); gtk_box_pack_start( GTK_BOX( box ),box_group,FALSE,FALSE,0 ); gtk_widget_show( box_group ); named_Draw_button = gtk_button_new_with_label( "Draw" ); gtk_signal_connect( GTK_OBJECT( named_Draw_button ), "clicked", GTK_SIGNAL_FUNC( named_Draw_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ),named_Draw_button,FALSE,FALSE,0 ); gtk_widget_show( named_Draw_button ); named_Permute_button = gtk_button_new_with_label( "Permute" ); gtk_signal_connect( GTK_OBJECT( named_Permute_button ), "clicked", GTK_SIGNAL_FUNC( named_Permute_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ),named_Permute_button,FALSE,FALSE,0 ); gtk_widget_show( named_Permute_button ); named_Make_Key_button = gtk_button_new_with_label( "Make key" ); gtk_signal_connect( GTK_OBJECT( named_Make_Key_button ), "clicked", GTK_SIGNAL_FUNC( named_Make_Key_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ), named_Make_Key_button,FALSE,FALSE,0 ); gtk_widget_show( named_Make_Key_button ); gtk_widget_show_all( named_page ); named_label = gtk_label_new( "named" ); gtk_widget_show( named_label ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ),named_page,named_label ); /* Automatic page */ automatic_page = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( automatic_page ),2 ); box = gtk_vbox_new( FALSE,0 ); gtk_container_border_width( GTK_CONTAINER( box ),BORDER ); gtk_container_add( GTK_CONTAINER( automatic_page ),box ); table = gtk_table_new( 3,2,FALSE ); gtk_box_pack_start( GTK_BOX( box ),table,FALSE,TRUE,0 ); label = gtk_label_new( "key:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); automatic_Key = gtk_entry_new_with_max_length( MAX_KEY ); gtk_signal_connect( GTK_OBJECT( automatic_Key ), "activate", GTK_SIGNAL_FUNC( automatic_Enter_Callback ), automatic_Key ); gtk_table_attach( GTK_TABLE( table ),automatic_Key,1,2,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); label = gtk_label_new( "generation:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); automatic_Generation = gtk_entry_new_with_max_length( MAX_GENERATION ); gtk_entry_set_text( GTK_ENTRY( automatic_Generation ),DEF_GENERATION ); gtk_table_attach( GTK_TABLE( table ),automatic_Generation,1,2,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); label = gtk_label_new( "speed:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); adjustment = (GtkAdjustment*)gtk_adjustment_new( DEF_SPEED, MIN_SPEED, MAX_SPEED, SPEED_STEP, SPEED_PAGE, 0.0 ); automatic_Speed = gtk_spin_button_new( adjustment,0,0 ); gtk_table_attach( GTK_TABLE( table ),automatic_Speed,1,2,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); box_group = gtk_hbox_new( FALSE,BORDER ); gtk_container_border_width( GTK_CONTAINER( box_group ),BORDER ); gtk_box_pack_start( GTK_BOX( box ),box_group,FALSE,FALSE,0 ); gtk_widget_show( box_group ); automatic_Draw_button = gtk_button_new_with_label( "Draw" ); gtk_signal_connect( GTK_OBJECT( automatic_Draw_button ), "clicked", GTK_SIGNAL_FUNC( automatic_Draw_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ), automatic_Draw_button,FALSE,FALSE,0 ); gtk_widget_show( automatic_Draw_button ); automatic_Next_button = gtk_button_new_with_label( "Next" ); gtk_signal_connect( GTK_OBJECT( automatic_Next_button ), "clicked", GTK_SIGNAL_FUNC( automatic_Next_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ), automatic_Next_button,FALSE,FALSE,0 ); gtk_widget_show( automatic_Next_button ); automatic_Run_button = gtk_button_new_with_label( "Run" ); gtk_signal_connect( GTK_OBJECT( automatic_Run_button ), "clicked", GTK_SIGNAL_FUNC( automatic_Run_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ), automatic_Run_button,FALSE,FALSE,0 ); gtk_widget_show( automatic_Run_button ); automatic_Stop_button = gtk_button_new_with_label( "Stop" ); gtk_signal_connect( GTK_OBJECT( automatic_Stop_button ), "clicked", GTK_SIGNAL_FUNC( automatic_Stop_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ), automatic_Stop_button,FALSE,FALSE,0 ); gtk_widget_show( automatic_Stop_button ); gtk_widget_set_sensitive( automatic_Stop_button,FALSE ); gtk_widget_show_all( automatic_page ); automatic_label = gtk_label_new( "automatic" ); gtk_widget_show( automatic_label ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), automatic_page,automatic_label ); /* List page */ list_page = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( list_page ),2 ); box = gtk_vbox_new( FALSE,0 ); gtk_container_border_width( GTK_CONTAINER( box ),BORDER ); gtk_container_add( GTK_CONTAINER( list_page ),box ); table = gtk_table_new( 3,3,FALSE ); gtk_box_pack_start( GTK_BOX( box ),table,FALSE,TRUE,0 ); label = gtk_label_new( "file:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); list_Filespec = gtk_entry_new_with_max_length( MAX_FILESPEC ); gtk_table_attach( GTK_TABLE( table ),list_Filespec,1,2,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); list_Open_button = gtk_button_new_with_label( "Open ..." ); gtk_signal_connect( GTK_OBJECT( list_Open_button ), "clicked", GTK_SIGNAL_FUNC( list_Open_Callback ), NULL ); gtk_table_attach( GTK_TABLE( table ),list_Open_button,2,3,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); gtk_widget_show( list_Open_button ); label = gtk_label_new( "speed:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); adjustment = (GtkAdjustment*)gtk_adjustment_new( DEF_SPEED, MIN_SPEED, MAX_SPEED, SPEED_STEP, SPEED_PAGE, 0.0 ); list_Speed = gtk_spin_button_new( adjustment,0,0 ); gtk_table_attach( GTK_TABLE( table ),list_Speed,1,2,2,3, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); label = gtk_label_new( "loop:" ); gtk_misc_set_alignment( GTK_MISC( label ),1.0,0.5 ); gtk_table_attach( GTK_TABLE( table ),label,0,1,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); list_option_Loop = gtk_option_menu_new(); gtk_widget_show( list_option_Loop ); list_Loop = gtk_menu_new(); for ( i = 0; i < LOOPS; i++ ) { menu_item = gtk_menu_item_new_with_label( loop_table[i].label ); gtk_signal_connect( GTK_OBJECT( menu_item ), "activate", (GtkSignalFunc)loop_Select_Callback, (gpointer)loop_table[i].id ); gtk_menu_append( GTK_MENU( list_Loop ),menu_item ); gtk_widget_show( menu_item ); } gtk_menu_set_active( GTK_MENU( list_Loop ),loop ); gtk_option_menu_set_menu( GTK_OPTION_MENU( list_option_Loop ),list_Loop ); gtk_table_attach( GTK_TABLE( table ),list_option_Loop,1,2,3,4, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,PAD,PAD ); box_group = gtk_hbox_new( FALSE,BORDER ); gtk_container_border_width( GTK_CONTAINER( box_group ),BORDER ); gtk_box_pack_start( GTK_BOX( box ),box_group,FALSE,FALSE,0 ); gtk_widget_show( box_group ); list_Run_button = gtk_button_new_with_label( "Run" ); gtk_signal_connect( GTK_OBJECT( list_Run_button ), "clicked", GTK_SIGNAL_FUNC( list_Run_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ),list_Run_button,FALSE,FALSE,0 ); gtk_widget_show( list_Run_button ); list_Stop_button = gtk_button_new_with_label( "Stop" ); gtk_signal_connect( GTK_OBJECT( list_Stop_button ), "clicked", GTK_SIGNAL_FUNC( list_Stop_Callback ), NULL ); gtk_box_pack_start( GTK_BOX( box_group ),list_Stop_button,FALSE,FALSE,0 ); gtk_widget_show( list_Stop_button ); gtk_widget_set_sensitive( list_Stop_button,FALSE ); gtk_widget_show_all( list_page ); list_label = gtk_label_new( "list" ); gtk_widget_show( list_label ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ),list_page,list_label ); /* show notebook */ gtk_notebook_set_page( GTK_NOTEBOOK( notebook ),method ); gtk_widget_show( notebook ); /* horizontal seperator */ separator = gtk_hseparator_new(); gtk_box_pack_start( GTK_BOX( window_box ),separator,FALSE,TRUE,0 ); gtk_widget_show( separator ); /* buttons */ box_group = gtk_hbox_new( FALSE,BORDER ); gtk_container_border_width( GTK_CONTAINER( box_group ),BORDER ); gtk_box_pack_start( GTK_BOX( window_box ),box_group,FALSE,TRUE,0 ); gtk_widget_show( box_group ); /* Quit */ Quit_button = gtk_button_new_with_label( "Quit" ); gtk_signal_connect( GTK_OBJECT( Quit_button ), "clicked", GTK_SIGNAL_FUNC( control_Quit ), snowflake_window ); gtk_box_pack_start( GTK_BOX( box_group ),Quit_button,FALSE,TRUE,0 ); gtk_widget_show( Quit_button ); /* Save Image ... */ Save_Image_button = gtk_button_new_with_label( "Save Image ..." ); gtk_signal_connect( GTK_OBJECT( Save_Image_button ), "clicked", GTK_SIGNAL_FUNC( control_Save_Image ), snowflake_window ); gtk_box_pack_start( GTK_BOX( box_group ),Save_Image_button,FALSE,TRUE,0 ); gtk_widget_show( Save_Image_button ); gtk_widget_set_sensitive( Save_Image_button,FALSE ); /* Save Design ... */ Save_Design_button = gtk_button_new_with_label( "Save Design ..." ); gtk_signal_connect( GTK_OBJECT( Save_Design_button ), "clicked", GTK_SIGNAL_FUNC( control_Save_Design ), snowflake_window ); gtk_box_pack_start( GTK_BOX( box_group ),Save_Design_button,FALSE,TRUE,0 ); gtk_widget_show( Save_Design_button ); /* Add Design */ Add_Design_button = gtk_button_new_with_label( "Add Design" ); gtk_signal_connect( GTK_OBJECT( Add_Design_button ), "clicked", GTK_SIGNAL_FUNC( control_Add_Design ), snowflake_window ); gtk_box_pack_start( GTK_BOX( box_group ),Add_Design_button,FALSE,TRUE,0 ); gtk_widget_show( Add_Design_button ); gtk_widget_set_sensitive( Add_Design_button,FALSE ); /* About */ About_button = gtk_button_new_with_label( "About" ); gtk_signal_connect( GTK_OBJECT( About_button ), "clicked", GTK_SIGNAL_FUNC( control_About ), snowflake_window ); gtk_box_pack_start( GTK_BOX( box_group ),About_button,FALSE,TRUE,0 ); gtk_widget_show( About_button ); /* show window */ gtk_widget_show( snowflake_window ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* popup an error dialog */ static void error_Dialog( gchar* message ) { GtkWidget* label; GtkWidget* button; error_dialog = gtk_dialog_new(); gtk_signal_connect( GTK_OBJECT( error_dialog ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroyed ), &error_dialog ); gtk_window_set_title( GTK_WINDOW( error_dialog ),"Error"); gtk_container_border_width( GTK_CONTAINER( error_dialog ),BORDER ); label = gtk_label_new( message ); gtk_misc_set_padding( GTK_MISC( label ),BORDER,BORDER ); gtk_box_pack_start( GTK_BOX( GTK_DIALOG( error_dialog )->vbox ), label,TRUE,TRUE,0 ); gtk_widget_show( label ); button = gtk_button_new_with_label( "OK" ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( error_Callback ), NULL ); GTK_WIDGET_SET_FLAGS( button,GTK_CAN_DEFAULT ); gtk_box_pack_start( GTK_BOX( GTK_DIALOG( error_dialog )->action_area ), button,TRUE,TRUE,0 ); gtk_widget_grab_default( button ); gtk_widget_show( button ); gtk_widget_show( error_dialog ); gtk_widget_set_sensitive( snowflake_window,FALSE ); gtk_grab_add( error_dialog ); } /* error dialog 'Ok' */ static void error_Callback( GtkWidget* widget,GtkWidget* window ) { gtk_widget_set_sensitive( snowflake_window,TRUE ); gtk_grab_remove( error_dialog ); gtk_widget_destroy( error_dialog ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void iconify_window( GtkWidget* window ) { GdkWindowPrivate* window_private; window_private = (GdkWindowPrivate*)( snowflake_window->window ); XIconifyWindow( window_private->xdisplay, window_private->xwindow, gdk_screen ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */