add .gitignore
[xgalaxy.git] / menuaction.c
1 #include <stdio.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <gtk/gtk.h>
6 #include <math.h>
7 #include <pthread.h>
8
9 #include "tools.h"
10 #include "tmalloc.h"
11 #include "xgalaxy.h"
12
13 void
14 galaxy_set_title() {
15         char *buf;
16
17         buf = g_malloc( strlen("Galaxy - ") + (( XGalaxy.filename ) ? strlen(XGalaxy.filename) : 0) + 1);
18         if ( XGalaxy.filename ) {
19                 char *ptr = strrchr(XGalaxy.filename,'/');
20                 if ( !ptr ) ptr = XGalaxy.filename; else  ptr++;
21                 sprintf(buf,"Galaxy - %s", ptr);
22         } else 
23                 sprintf(buf,"Galaxy");
24
25         gtk_window_set_title (GTK_WINDOW(XGalaxy.window), buf);
26         g_free(buf); 
27 }
28
29 void 
30 clearData( GtkWidget *w, gpointer   data ) {
31         if ( XGalaxy.runing ) return;
32
33         gtk_label_set_text( GTK_LABEL(XGalaxy.dataEnergyField), "0");
34         gtk_label_set_text( GTK_LABEL(XGalaxy.dataImpulseField), "0");
35         gtk_label_set_text( GTK_LABEL(XGalaxy.dataMomentField), "0");
36
37         gtk_entry_set_text(GTK_ENTRY(XGalaxy.deltaField), "3600");
38         gtk_entry_set_text(GTK_ENTRY(XGalaxy.errorField), "1e-8");
39         gtk_list_store_clear( GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(XGalaxy.dataField))) );
40
41         if ( XGalaxy.filename ) {
42                 g_free(XGalaxy.filename);
43                 XGalaxy.filename=NULL;
44                 galaxy_set_title();
45         }
46         freeStarEntry();
47         XGalaxy.Xangle = XGalaxy.Yangle = XGalaxy.Zangle = 0.0;
48         gtk_range_set_value(GTK_RANGE(XGalaxy.XSlider), 0);
49         gtk_range_set_value(GTK_RANGE(XGalaxy.YSlider), 0);
50         gtk_range_set_value(GTK_RANGE(XGalaxy.ZSlider), 0);
51         memset( &(XGalaxy.angle), 0, sizeof(XGalaxy.angle) );
52         XGalaxy.angle.w=1;
53
54         gtk_clist_clear( GTK_CLIST(XGalaxy.resField) );
55         gtk_label_set_text( GTK_LABEL(XGalaxy.resEnergyField), "0");
56         gtk_label_set_text( GTK_LABEL(XGalaxy.resImpulseField), "0");
57         gtk_label_set_text( GTK_LABEL(XGalaxy.resMomentField), "0");
58         gtk_label_set_text( GTK_LABEL(XGalaxy.resDeltaField), "0");
59         gtk_label_set_text( GTK_LABEL(XGalaxy.resTimeField), "0");
60
61         clearDraw();
62         drawGalaxy();
63 }
64
65 void
66 saveData() {
67         FILE *out = fopen(XGalaxy.filename, "w");
68         u_int32_t i;
69
70         if ( !out ) {
71                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
72                                   GTK_DIALOG_DESTROY_WITH_PARENT,
73                                   GTK_MESSAGE_ERROR,
74                                   GTK_BUTTONS_CLOSE,
75                                   "Error saving file '%s': %s",
76                                   XGalaxy.filename, g_strerror (errno));
77                 gtk_dialog_run (GTK_DIALOG (dialog));
78                 gtk_widget_destroy(dialog);
79                 return;
80         }
81
82         fprintf(out, "delta=%G\n", atof( gtk_entry_get_text( GTK_ENTRY(XGalaxy.deltaField) ) ) ); 
83         fprintf(out, "error=%G\n", atof( gtk_entry_get_text( GTK_ENTRY(XGalaxy.errorField) ) ) ); 
84         fprintf(out, "\n");
85         for(i=0;i<XGalaxy.nentry;i++)
86                 fprintf(out,"%G\t%G\t%G\t%G\t%G\t%G\t%G\n",
87                         XGalaxy.entry[i].mass,
88                         XGalaxy.entry[i].c.x,
89                         XGalaxy.entry[i].c.y,
90                         XGalaxy.entry[i].c.z,
91                         XGalaxy.entry[i].v.x,
92                         XGalaxy.entry[i].v.y,
93                         XGalaxy.entry[i].v.z
94                 );
95
96         fclose(out);
97 }
98
99
100 void 
101 saveAsFile( GtkWidget *w, gpointer   data ) {
102         GtkWidget *dialog = gtk_file_chooser_dialog_new("Save as", GTK_WINDOW(XGalaxy.window), GTK_FILE_CHOOSER_ACTION_SAVE,
103                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
104                 NULL);
105
106         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
107                 if ( XGalaxy.filename ) g_free(XGalaxy.filename);
108                 XGalaxy.filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
109                 galaxy_set_title();
110
111                 saveData();
112         }
113
114         gtk_widget_destroy (dialog); 
115 }
116
117 void 
118 saveFile( GtkWidget *w, gpointer   data ) {
119         if ( !XGalaxy.filename ) {
120                 saveAsFile(w, data);
121         } else {
122                 saveData();
123         }
124 }
125
126 void
127 loadData() {
128         FILE *in;
129         char buf[4096];
130         double  tmp;
131         Star    star;
132         GtkTreeIter   iter;
133         GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(XGalaxy.dataField)));
134
135         if ( XGalaxy.runing )
136                 return;
137
138         in = fopen(XGalaxy.filename, "r");
139         if ( !in ) {
140                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
141                                   GTK_DIALOG_DESTROY_WITH_PARENT,
142                                   GTK_MESSAGE_ERROR,
143                                   GTK_BUTTONS_CLOSE,
144                                   "Error opening file '%s': %s",
145                                   XGalaxy.filename, g_strerror (errno));
146                 gtk_dialog_run (GTK_DIALOG (dialog));
147                 gtk_widget_destroy(dialog);
148                 g_free(XGalaxy.filename);
149                 XGalaxy.filename=NULL;
150                 return;
151         }
152
153         while(fgets(buf, 4096, in)) {
154                 if ( strncmp("delta", buf, strlen("delta"))==0 ) {
155                         sscanf(buf,"delta=%lG", &tmp);
156                         sprintf(buf,"%G", tmp);
157                         gtk_entry_set_text( GTK_ENTRY(XGalaxy.deltaField), buf );
158                 } else if ( strncmp("error", buf, strlen("error"))==0 ) {
159                         sscanf(buf,"error=%lG", &tmp);
160                         sprintf(buf,"%G", tmp);
161                         gtk_entry_set_text( GTK_ENTRY(XGalaxy.errorField), buf );
162                 } else if ( strlen(buf)>6 ) {
163                         sscanf(buf,"%lG\t%lG\t%lG\t%lG\t%lG\t%lG\t%lG",
164                                 &(star.mass),
165                                 &(star.c.x),
166                                 &(star.c.y),
167                                 &(star.c.z),
168                                 &(star.v.x),
169                                 &(star.v.y),
170                                 &(star.v.z)
171                         );
172                         gtk_list_store_append( store, &iter );
173                         sprintf(buf, "%G", star.mass);
174                         gtk_list_store_set( store, &iter, 1, buf, -1);
175                         sprintf(buf, "%G", star.c.x);
176                         gtk_list_store_set( store, &iter, 2, buf, -1);
177                         sprintf(buf, "%G", star.c.y);
178                         gtk_list_store_set( store, &iter, 3, buf, -1);
179                         sprintf(buf, "%G", star.c.z);
180                         gtk_list_store_set( store, &iter, 4, buf, -1);
181                         sprintf(buf, "%G", star.v.x);
182                         gtk_list_store_set( store, &iter, 5, buf, -1);
183                         sprintf(buf, "%G", star.v.y);
184                         gtk_list_store_set( store, &iter, 6, buf, -1);
185                         sprintf(buf, "%G", star.v.z);
186                         gtk_list_store_set( store, &iter, 7, buf, -1);
187                         addEntry(&star);
188                 }
189         }
190         fclose(in);
191         gtk_notebook_set_current_page(GTK_NOTEBOOK(XGalaxy.notebook), 0);
192         cntEntry();
193 }
194
195 void
196 openFile( GtkWidget *w, gpointer   data ) {
197         if ( !XGalaxy.runing ) {
198                 GtkWidget *dialog = gtk_file_chooser_dialog_new("Open", GTK_WINDOW(XGalaxy.window), GTK_FILE_CHOOSER_ACTION_OPEN,
199                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
200                         NULL);
201
202                 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
203                         clearData(w,data);
204                         if ( XGalaxy.filename ) g_free(XGalaxy.filename);
205                         XGalaxy.filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
206                         galaxy_set_title();
207                         loadData();
208                 }
209
210                 gtk_widget_destroy (dialog);
211         }
212 }
213
214 void
215 showAbout(  GtkWidget *w, gpointer   data ) {
216 /* 2.6 only
217         GtkWidget *dialog = gtk_about_dialog_new() ;
218
219         gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), "XGalaxy");
220         gtk_about_dialog_get_comments(GTK_ABOUT_DIALOG(dialog), "Gravity modeling");
221         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "1.0");
222         gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "COPYRIGHT");
223         gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog),"(X)Galaxy is under BSD license");
224         gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog),"http://www.sigaev.ru");
225         gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog),"Teodor Sigaev");
226
227          gtk_show_about_dialog(GTK_WINDOW(XGalaxy.window),
228                 "name", "XGalaxy",
229                 "comments", "Gravity modeling",
230                 "version", "1.0",
231                 "copyright", "COPYRIGHT",
232                 "license", "XGalaxy is under BSD license",
233                 "website", "http://www.sigaev.ru",
234                 "authors", "Teodor Sigaev",
235                 NULL);
236 */
237         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
238                 GTK_DIALOG_MODAL,
239                 GTK_MESSAGE_INFO,
240                 GTK_BUTTONS_CLOSE,
241                 "XGalaxy - gravity modeling software.\nCopyright Teodor Sigaev <teodor@sigaev.ru>, 2004.\nPublished under BSD license"
242         );
243         gtk_dialog_run (GTK_DIALOG (dialog));
244         gtk_widget_destroy(dialog);
245 }
246
247 void
248 fillResult(int clearres) {
249         char buf[128];
250         int     i;
251
252
253         
254         pthread_mutex_lock(&(XGalaxy.mutex));
255         sprintf(buf,"%G",XGalaxy.galaxy.kineticEnergy + XGalaxy.galaxy.potentialEnergy);
256         gtk_label_set_text( GTK_LABEL(XGalaxy.resEnergyField), buf);
257
258         sprintf(buf,"%G",XGalaxy.galaxy.Impulse);
259         gtk_label_set_text( GTK_LABEL(XGalaxy.resImpulseField), buf);
260
261         sprintf(buf,"%G",XGalaxy.galaxy.Moment);
262         gtk_label_set_text( GTK_LABEL(XGalaxy.resMomentField), buf);
263
264         sprintf(buf,"%G",XGalaxy.galaxy.delta);
265         gtk_label_set_text( GTK_LABEL(XGalaxy.resDeltaField), buf);
266
267         sprintf(buf,"%G",XGalaxy.galaxy.elapsedTime);
268         gtk_label_set_text( GTK_LABEL(XGalaxy.resTimeField), buf);
269
270         memcpy( XGalaxy.tmpentry, XGalaxy.galaxy.stars, sizeof(Star)*XGalaxy.galaxy.nstars );
271         pthread_mutex_unlock(&(XGalaxy.mutex));
272
273         gtk_clist_freeze( GTK_CLIST(XGalaxy.resField) );
274         if ( clearres ) {
275                 gchar *data[7] = { "", "", "", "", "", "", "" };
276                 gtk_clist_clear( GTK_CLIST(XGalaxy.resField) );
277                 for(i=0;i<XGalaxy.nentry;i++)
278                         gtk_clist_append(GTK_CLIST(XGalaxy.resField), data);
279         }
280
281
282         for(i=0;i<XGalaxy.nentry;i++) {
283                 sprintf(buf,"%G", XGalaxy.tmpentry[i].mass);
284                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 0, buf);
285                 sprintf(buf,"%G", XGalaxy.tmpentry[i].c.x);
286                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 1, buf);
287                 sprintf(buf,"%G", XGalaxy.tmpentry[i].c.y);
288                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 2, buf);
289                 sprintf(buf,"%G", XGalaxy.tmpentry[i].c.z);
290                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 3, buf);
291                 sprintf(buf,"%G", XGalaxy.tmpentry[i].v.x);
292                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 4, buf);
293                 sprintf(buf,"%G", XGalaxy.tmpentry[i].v.y);
294                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 5, buf);
295                 sprintf(buf,"%G", XGalaxy.tmpentry[i].v.z);
296                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 6, buf);
297                 sprintf(buf,"%G", sqrt( XGalaxy.tmpentry[i].v.z*XGalaxy.tmpentry[i].v.z + XGalaxy.tmpentry[i].v.y*XGalaxy.tmpentry[i].v.y + XGalaxy.tmpentry[i].v.x*XGalaxy.tmpentry[i].v.x ) );
298                 gtk_clist_set_text(GTK_CLIST(XGalaxy.resField), i, 7, buf);
299         }       
300         gtk_clist_thaw( GTK_CLIST(XGalaxy.resField) );
301 }
302
303 static u_int32_t cycles=0;
304 gboolean
305 fillResultByTimeout(gpointer data) {
306         if ( XGalaxy.runing==0 )
307                 return FALSE;
308
309
310         if ( !XGalaxy.paused ) {
311                 struct timeval begin;
312                 XGalaxy.runTime -= ((double)XG_TIME_TICK)/1000.0;
313
314                 if ( XGalaxy.runTime >= 0 ) 
315                         return TRUE;
316                 
317                 gettimeofday( &begin, NULL );
318                 switch( XGalaxy.page_active ) {
319                         case 2: 
320                                 if ( cycles++ % (int)ceil(200/XG_TIME_TICK) == 0 ) 
321                                         fillResult(FALSE);
322                                 if (XGalaxy.trace)
323                                         drawStars(); 
324                                 break;
325                         case 1: 
326                                 drawGalaxy(); 
327                                 break;
328                         default: 
329                                 if (XGalaxy.trace)
330                                         drawStars(); 
331                                 break;
332                 }
333
334                 XGalaxy.runTime = elapsedtime( &begin );
335
336                 if ( cycles > 2000000000 )
337                         cycles=1;
338         }
339
340         return TRUE;
341
342
343 gboolean
344 show_resCList(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
345         g_print("EVENT\n");     
346         return FALSE;
347 }
348
349 void*
350 runingGravity(void *notneed) {
351         while( XGalaxy.request_to_exit == 0 ) {
352                 liveGalaxy( &(XGalaxy.galaxy), &(XGalaxy.mutex) );
353                 pthread_yield();
354         }
355         XGalaxy.request_to_exit = 0;
356
357         return NULL;
358 }
359
360 int
361 startGravity() {
362         int rc;
363
364         if ( (rc=pthread_create(&(XGalaxy.thread), NULL, runingGravity, NULL))!=0 ) {
365                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
366                                   GTK_DIALOG_DESTROY_WITH_PARENT,
367                                   GTK_MESSAGE_ERROR,
368                                   GTK_BUTTONS_CLOSE,
369                                   "Error starting thread': %s",
370                                   g_strerror (errno));
371                 gtk_dialog_run (GTK_DIALOG (dialog));
372                 gtk_widget_destroy(dialog);
373         }
374         return rc;
375 }
376
377 void 
378 actionStop( GtkWidget *w, gpointer   data ) {
379         if ( !XGalaxy.runing )
380                 return;
381
382         if ( !XGalaxy.paused ) {
383                 XGalaxy.request_to_exit = 1;
384                 /* wait thread */
385                 while(XGalaxy.request_to_exit);
386         }        
387
388         fillResult(FALSE);
389         freeGalaxy(&(XGalaxy.galaxy));  
390
391         XGalaxy.locksignal=1;   
392         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonPause), FALSE);    
393         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), FALSE);      
394         g_object_set(G_OBJECT(XGalaxy.errorField),  "editable", TRUE, NULL);
395         g_object_set(G_OBJECT(XGalaxy.deltaField),  "editable", TRUE, NULL);
396         XGalaxy.locksignal=0;
397
398         XGalaxy.runing = XGalaxy.paused = XGalaxy.request_to_exit = 0;
399         clearDraw();
400         if ( XGalaxy.drawaxis ) drawAxis();
401         drawGalaxy();
402 }
403
404 void
405 actionPause( GtkWidget *w, gpointer   data ) {
406         if (XGalaxy.locksignal)
407                 return;
408         XGalaxy.locksignal=1;   
409         if ( !XGalaxy.runing ) {
410                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonPause), FALSE);    
411                 XGalaxy.locksignal=0;   
412                 return;
413         }
414
415         if ( XGalaxy.paused ) {
416                 if ( startGravity() ) {
417                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonPause), TRUE);
418                         XGalaxy.locksignal=0;   
419                         return;
420                 }
421                 XGalaxy.paused=XGalaxy.request_to_exit=0; 
422                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonPause), FALSE);
423                 XGalaxy.locksignal=0;   
424                 return;
425         }
426  
427         XGalaxy.request_to_exit = 1;
428         /* wait thread */
429         while(XGalaxy.request_to_exit);
430         
431         XGalaxy.paused = 1;
432         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonPause), TRUE);
433         XGalaxy.locksignal=0;   
434         fillResult(FALSE);
435         drawGalaxy();
436 }
437
438 void
439 actionRun( GtkWidget *w, gpointer   data ) {
440         int i;
441
442         if (XGalaxy.locksignal)
443                 return;
444
445         XGalaxy.locksignal=1;   
446         if ( XGalaxy.runing ) {
447                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), TRUE);
448                 XGalaxy.locksignal=0;   
449                 return;
450         }
451
452         if ( XGalaxy.nentry < 2 ) {
453                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
454                                   GTK_DIALOG_DESTROY_WITH_PARENT,
455                                   GTK_MESSAGE_ERROR,
456                                   GTK_BUTTONS_CLOSE,
457                                   "Too small number of entries");
458                 gtk_dialog_run (GTK_DIALOG (dialog));
459                 gtk_widget_destroy(dialog);
460
461                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), FALSE);
462                 XGalaxy.locksignal=0;   
463                 return;
464         }
465
466         for(i=0;i<XGalaxy.nentry;i++) 
467                 if ( XGalaxy.entry[i].mass==0.0 || !finite(XGalaxy.entry[i].mass) ) {
468                         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(XGalaxy.window),
469                                   GTK_DIALOG_DESTROY_WITH_PARENT,
470                                   GTK_MESSAGE_ERROR,
471                                   GTK_BUTTONS_CLOSE,
472                                   "Zero mass");
473                         gtk_dialog_run (GTK_DIALOG (dialog));
474                         gtk_widget_destroy(dialog);
475                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), FALSE);
476                         XGalaxy.locksignal=0;   
477                         return;
478                 }
479                 
480
481         
482         initGalaxy(&(XGalaxy.galaxy), XGalaxy.nentry);
483         memcpy(XGalaxy.galaxy.stars, XGalaxy.entry, XGalaxy.nentry*sizeof(Star));
484
485         g_object_set(G_OBJECT(XGalaxy.errorField),  "editable", FALSE, NULL);
486         g_object_set(G_OBJECT(XGalaxy.deltaField),  "editable", FALSE, NULL);
487
488         XGalaxy.galaxy.desiredDelta = atof(gtk_entry_get_text(GTK_ENTRY(XGalaxy.deltaField)));
489         XGalaxy.galaxy.errorLimit = atof(gtk_entry_get_text(GTK_ENTRY(XGalaxy.errorField)));
490         initLiveGalaxy( &(XGalaxy.galaxy) );
491         fillResult(TRUE);
492         fitGalaxy();
493         drawGalaxy();
494
495         if ( startGravity() ) { 
496                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), FALSE);
497                 XGalaxy.locksignal=0;   
498                 freeGalaxy(&(XGalaxy.galaxy)); 
499                 g_object_set(G_OBJECT(XGalaxy.errorField),  "editable", TRUE, NULL);
500                 g_object_set(G_OBJECT(XGalaxy.deltaField),  "editable", TRUE, NULL);
501                 return; 
502         }
503
504         XGalaxy.runing=1;
505         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(XGalaxy.buttonRun), TRUE);
506         XGalaxy.paused=XGalaxy.request_to_exit=0;
507         XGalaxy.locksignal=0;   
508         g_timeout_add(XG_TIME_TICK, fillResultByTimeout, NULL);
509 }
510
511