1
2 /*
3 * Ump - Unnamed Math Program
4 * Copyright (c) 2004-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5 *
6 * See main.cpp
7 */
8
9 #include "ump_advancedwin.h"
10 #include "ump_aboutwin.h"
11 #include "ump_simplewin.h"
12 #include "ump_editor.h"
13 #include "ump_graphwin.h"
14 #include "ump_prefwin.h"
15 #include "matrix_editor.h"
16 #include "main.h"
17 #include "math2.h"
18 #include "utf8_string.h"
19 #include "keyfile.h"
20
21 Vector<utf8_string> advanced_history;
22
23 GtkWidget *advancedwin = 0, *advancedwin_menu, *advanced_vbox, *advanced_button;
24
25
26 void advancedwin_close(void);
27 void advanced_calculate(void);
28 void advanced_file_load(void);
29 void advanced_file_save_as(void);
30 void advanced_opt_radian(void);
31 void advanced_opt_degree(void);
32 void advanced_opt_format(void);
33 GtkWidget *advanced_combo, *advanced_textview, *advanced_degfix;
34 GtkTextBuffer *advanced_textbuffer;
35
aboutwin_show_advanced(void)36 void aboutwin_show_advanced(void) { aboutwin_show(GTK_WINDOW(advancedwin)); }
prefwin_show_advanced(void)37 void prefwin_show_advanced(void) { prefwin_show(GTK_WINDOW(advancedwin)); }
38
39
40 void advanced_entry_insert(GtkEditable *editable,gchar *new_text,gint new_text_length,gint *position);
41
42
43
degfix_changed(void)44 void degfix_changed(void)
45 {
46 const Complex degree( PI/180.0 ), radian( 1.0 );
47
48 if(advancedwin == 0)
49 return;
50
51 if( math::degfix == radian )
52 gtk_label_set_text(GTK_LABEL(advanced_degfix), _("Radian") );
53 else if( math::degfix == degree )
54 gtk_label_set_text(GTK_LABEL(advanced_degfix), _("Degree") );
55 else
56 gtk_label_set_text(GTK_LABEL(advanced_degfix), PRG_NAME );
57 }
58
advancedwin_build_menu(void)59 GtkWidget* advancedwin_build_menu(void)
60 {
61 GtkActionGroup *actions;
62 GtkUIManager *ui_manager;
63 GError *error = NULL;
64 static const gchar *menu =
65 "<ui>"
66 " <menubar name='MenuBar'>"
67 " <menu action='FileMenu'>"
68 " <menuitem action='Clear'/>"
69 " <menuitem action='SaveAs'/>"
70 " <separator/>"
71 " <menuitem action='Load'/>"
72 " <separator/>"
73 " <menuitem action='Close'/>"
74 " <separator/>"
75 " <menuitem action='Quit'/>"
76 " </menu>"
77 " <menu action='PrefMenu'>"
78 " <menuitem action='Radian'/>"
79 " <menuitem action='Degree'/>"
80 " <separator/>"
81 " <menuitem action='Preferences'/>"
82 " </menu>"
83 " <menu action='ToolsMenu'>"
84 " <menuitem action='Simple'/>"
85 " <menuitem action='Editor'/>"
86 " <menuitem action='Graphtool'/>"
87 " <menuitem action='MatrixEdit'/>"
88 " </menu>"
89 " <menuitem action='About'/>"
90 " </menubar>"
91 "</ui>";
92 GtkActionEntry entries[] = {
93 { "FileMenu", NULL, menu_file },
94 { "Clear", GTK_STOCK_NEW, _("_Clear"), "<ctrl>N", NULL, G_CALLBACK(advancedwin_file_clear) },
95 { "SaveAs", GTK_STOCK_SAVE_AS, menu_file_save_as, "<ctrl>S", NULL, G_CALLBACK(advanced_file_save_as) },
96 { "Load", GTK_STOCK_EXECUTE, _("Load a .Ump-file..."),NULL, NULL, G_CALLBACK(advanced_file_load) },
97 { "Close", GTK_STOCK_CLOSE, menu_file_close, "<ctrl>W", NULL, G_CALLBACK(advancedwin_close) },
98 { "Quit", GTK_STOCK_QUIT, menu_file_quit, "<ctrl>Q", NULL, G_CALLBACK(UMP_gtk_quit) },
99 { "PrefMenu", NULL, menu_pref },
100 { "Radian", NULL, _("_Radian"), NULL, NULL, G_CALLBACK(advanced_opt_radian) },
101 { "Degree", NULL, _("_Degree"), NULL, NULL, G_CALLBACK(advanced_opt_degree) },
102 { "Preferences", GTK_STOCK_PREFERENCES, menu_pref, NULL, NULL, G_CALLBACK(prefwin_show_advanced) },
103 { "ToolsMenu", NULL, menu_tools },
104 { "Simple", NULL, menu_tools_simple, NULL, NULL, G_CALLBACK(simplewin_show) },
105 { "Editor", NULL, menu_tools_editor, NULL, NULL, G_CALLBACK(editor_showwin) },
106 { "Graphtool", NULL, menu_tools_graphtool, NULL, NULL, G_CALLBACK(graphwin_show) },
107 { "MatrixEdit", NULL, menu_tools_matrixedit,NULL, NULL, G_CALLBACK(matrix_editor_show) },
108 { "About", NULL, menu_about, NULL, NULL, G_CALLBACK(aboutwin_show_advanced) }
109 };
110 guint n_entries = G_N_ELEMENTS(entries);
111
112 actions = gtk_action_group_new("Actions");
113 gtk_action_group_add_actions(actions, entries, n_entries, NULL);
114 ui_manager = gtk_ui_manager_new();
115 gtk_ui_manager_insert_action_group(ui_manager, actions, 0);
116 gtk_window_add_accel_group( GTK_WINDOW(advancedwin), gtk_ui_manager_get_accel_group(ui_manager) );
117 if(!gtk_ui_manager_add_ui_from_string(ui_manager, menu, -1, &error))
118 {
119 g_message("building menus failed: %s", error->message);
120 g_error_free(error);
121 return 0;
122 }
123 gtk_ui_manager_ensure_update(ui_manager);
124
125 return gtk_ui_manager_get_widget(ui_manager, "/MenuBar");
126 }
127
advancedwin_show(void)128 GtkWindow* advancedwin_show(void)
129 {
130 if(advancedwin == 0)
131 {
132 GtkWidget *advanced_hbox, *advanced_scrolled, *tmp;
133
134 advancedwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
135 gtk_widget_set_size_request(GTK_WIDGET(advancedwin), 150,100);
136 gtk_window_set_title(GTK_WINDOW(advancedwin), PRG_NAME );
137 g_signal_connect(GTK_OBJECT(advancedwin), "delete-event", G_CALLBACK(advancedwin_close), NULL);
138
139 advanced_vbox = gtk_vbox_new(FALSE, 0);
140 gtk_container_add(GTK_CONTAINER(advancedwin), advanced_vbox);
141
142
143 if((advancedwin_menu = advancedwin_build_menu()) == 0)
144 {
145 gtk_widget_destroy( advancedwin );
146 advancedwin = 0;
147 return 0;
148 }
149 gtk_box_pack_start(GTK_BOX(advanced_vbox), advancedwin_menu, FALSE, FALSE, 0);
150
151
152 advanced_textbuffer = gtk_text_buffer_new(NULL);
153
154 advanced_textview = gtk_text_view_new_with_buffer(advanced_textbuffer);
155 gtk_text_view_set_editable(GTK_TEXT_VIEW(advanced_textview),FALSE);
156 gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(advanced_textview),FALSE);
157
158 {
159 PangoFontDescription *font_desc;
160 font_desc = pango_font_description_from_string("Monospace 10");
161 gtk_widget_modify_font(advanced_textview, font_desc);
162 pango_font_description_free(font_desc);
163 }
164 {
165 GtkTextIter iter;
166 gtk_text_buffer_get_end_iter( advanced_textbuffer, &iter);
167 gtk_text_buffer_create_mark(advanced_textbuffer, "the_end", &iter, FALSE);
168 }
169 advancedwin_file_clear();
170
171
172 advanced_scrolled = gtk_scrolled_window_new( NULL, NULL);
173 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(advanced_scrolled), GTK_POLICY_AUTOMATIC,
174 GTK_POLICY_AUTOMATIC );
175
176 gtk_container_add(GTK_CONTAINER(advanced_scrolled), advanced_textview);
177
178
179 advanced_combo = gtk_combo_box_entry_new_text();
180 gtk_entry_set_max_length(GTK_ENTRY(GTK_BIN(advanced_combo)->child),2000);
181 g_signal_connect_swapped(GTK_OBJECT(GTK_BIN(advanced_combo)->child), "activate", G_CALLBACK(advanced_calculate), NULL);
182 g_signal_connect(GTK_OBJECT(GTK_BIN(advanced_combo)->child), "insert-text", G_CALLBACK(advanced_entry_insert), NULL);
183 if( advanced_history.get_size() == 0 )
184 gtk_combo_box_prepend_text(GTK_COMBO_BOX(advanced_combo), "");
185 else
186 {
187 for( int i=0; i<advanced_history.get_size(); i++ )
188 gtk_combo_box_append_text( GTK_COMBO_BOX(advanced_combo),
189 advanced_history[i]->c_str() );
190 }
191 #ifdef USE_AUTO_COMPLETION
192 {
193 GtkEntryCompletion *complete = gtk_entry_completion_new();
194 gtk_entry_completion_set_model( complete, gtk_combo_box_get_model( GTK_COMBO_BOX(advanced_combo) ) );
195 gtk_entry_completion_set_inline_completion( complete, TRUE );
196 gtk_entry_completion_set_text_column( complete, 0 );
197 gtk_entry_set_completion( GTK_ENTRY(GTK_BIN(advanced_combo)->child), complete );
198 }
199 #endif
200
201 advanced_button = gtk_button_new_with_mnemonic( _("Calculate") );
202 g_signal_connect_swapped(GTK_OBJECT(advanced_button), "clicked", G_CALLBACK(advanced_calculate), NULL);
203
204
205
206 gtk_box_pack_start(GTK_BOX(advanced_vbox), advanced_scrolled, TRUE, TRUE, 0);
207
208 advanced_hbox = gtk_hbox_new(FALSE, 0);
209 gtk_box_pack_start(GTK_BOX(advanced_hbox), advanced_combo, TRUE, TRUE, 0);
210 gtk_box_pack_start(GTK_BOX(advanced_hbox), advanced_button, FALSE, FALSE, 0);
211
212 gtk_box_pack_start(GTK_BOX(advanced_vbox), advanced_hbox, FALSE, FALSE, 0);
213
214 advanced_hbox = gtk_hbox_new(FALSE, 0);
215 advanced_degfix = gtk_label_new( "" );
216 gtk_misc_set_alignment(GTK_MISC(advanced_degfix), 0.0f, 0.5f);
217 gtk_misc_set_padding(GTK_MISC(advanced_degfix), 2, 2);
218 gtk_box_pack_start(GTK_BOX(advanced_hbox), advanced_degfix, FALSE, FALSE, 0);
219
220 tmp = gtk_statusbar_new();
221 gtk_box_pack_start(GTK_BOX(advanced_hbox), tmp, TRUE, TRUE, 0);
222
223 gtk_box_pack_start(GTK_BOX(advanced_vbox), advanced_hbox, FALSE, FALSE, 0);
224
225 gtk_window_resize(GTK_WINDOW(advancedwin),625,400);
226 gtk_widget_show_all(advancedwin);
227 gtk_widget_grab_focus(GTK_BIN(advanced_combo)->child);
228
229 degfix_changed();
230 open_windows |= ADVANCED_WIN;
231 }
232 else
233 gtk_window_present(GTK_WINDOW(advancedwin));
234
235 return GTK_WINDOW( advancedwin );
236 }
237
advanced_entry_insert(GtkEditable * editable,gchar * new_text,gint new_text_length,gint * position)238 void advanced_entry_insert(GtkEditable *editable, gchar *new_text, gint new_text_length,
239 gint *position)
240 {
241 const char *text;
242
243 if(new_text_length == 1)
244 {
245 text = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(advanced_combo)->child));
246 if(text[0] == '\0')
247 {
248 switch(new_text[0])
249 {
250 case '+': case '-': case '*':
251 case '/': case '\\': case '^':
252 gtk_editable_insert_text(editable, "ans ", 4, position);
253 }
254 }
255 }
256 }
advanced_add_line_in_combo(const char * text)257 void advanced_add_line_in_combo(const char *text)
258 {
259 utf8_string str(text);
260
261 if( advanced_history.get_size() == 0)
262 gtk_combo_box_remove_text( GTK_COMBO_BOX(advanced_combo), 0 );
263
264 for( int i=0; i<advanced_history.get_size(); i++ )
265 {
266 if( str == *advanced_history[i] )
267 {
268 gtk_combo_box_remove_text( GTK_COMBO_BOX(advanced_combo), i );
269 advanced_history.remove( i );
270 i = -1; // this restarts the search in history list
271 }
272 }
273
274 if( advanced_history.get_size() >= 100)
275 {
276 gtk_combo_box_remove_text( GTK_COMBO_BOX(advanced_combo), 0 );
277 advanced_history.remove( 0 );
278 }
279
280 gtk_combo_box_append_text( GTK_COMBO_BOX(advanced_combo), text );
281 advanced_history.append( str );
282 }
advanced_calculate(void)283 void advanced_calculate(void)
284 {
285 const char *text;
286
287 text = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(advanced_combo)->child));
288
289 for(int i=0;;i++)
290 {
291 if(text[i] == 0) // only spaces or tabs on this line
292 {
293 gtk_entry_set_text(GTK_ENTRY(GTK_BIN(advanced_combo)->child), "");
294 gtk_widget_grab_focus(GTK_BIN(advanced_combo)->child);
295 return;
296 }
297
298 if( text[i] != ' ' && text[i] != '\t' )
299 break;
300 }
301
302 advanced_add_line_in_combo( text );
303
304 advancedwin_showtext( "\n" );
305 advancedwin_showtext( text );
306 advancedwin_showtext( "\n" );
307
308 try
309 {
310 utf8_string str;
311 math::Variable *varpointer;
312
313 varpointer = math::global_varlist.get_pointer_rw( math::global_varlist.get_id("ans") );
314
315 calc_function.set_code( text );
316 calc_function.calc( varpointer );
317 calc_function.clear();
318
319 if( !varpointer->is_void() )
320 {
321 varpointer->append_to_string( str, format );
322 advancedwin_showtext( str );
323 advancedwin_showtext( "\n" );
324 }
325 }
326 catch(error_obj error)
327 {
328
329 advancedwin_showtext( "\n " );
330 advancedwin_showtext( error.msg );
331 advancedwin_showtext( "\n\n" );
332 }
333
334 gtk_entry_set_text(GTK_ENTRY( GTK_BIN(advanced_combo)->child), "" );
335 gtk_widget_grab_focus( GTK_BIN(advanced_combo)->child );
336 }
337
338
advancedwin_showtext(const utf8_string & string)339 void advancedwin_showtext(const utf8_string &string)
340 {
341 if(advancedwin == 0)
342 return;
343
344 GtkTextIter iter;
345
346 gtk_text_buffer_get_end_iter( advanced_textbuffer, &iter);
347 gtk_text_buffer_insert( advanced_textbuffer, &iter, string.c_str(), -1);
348
349 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(advanced_textview),
350 gtk_text_buffer_get_mark(advanced_textbuffer, "the_end"));
351 }
352
advanced_file_load(void)353 void advanced_file_load(void)
354 {
355 GtkWidget *file_chooser;
356 GtkFileFilter *filter;
357
358 file_chooser = gtk_file_chooser_dialog_new( "Select a file", GTK_WINDOW(advancedwin),
359 GTK_FILE_CHOOSER_ACTION_OPEN,
360 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
361 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL );
362
363 filter = gtk_file_filter_new();
364 gtk_file_filter_add_pattern(filter, "*.ump");
365 gtk_file_filter_set_name(filter, filter_ump_files);
366 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
367
368 filter = gtk_file_filter_new();
369 gtk_file_filter_add_pattern(filter, "*");
370 gtk_file_filter_set_name(filter, filter_all_files);
371 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
372
373 if(gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT)
374 {
375 math::CodeBlock code;
376 char *filename;
377
378 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
379 try
380 {
381 code.set_code_from_file( filename );
382 }
383 catch(error_obj error)
384 {
385 advancedwin_showtext(error.msg);
386 advancedwin_showtext("\n");
387 }
388 g_free(filename);
389 }
390
391 gtk_widget_destroy(file_chooser);
392 }
393
file_save(const char * filename)394 void file_save(const char *filename)
395 {
396 GtkTextIter start, end;
397 char *text;
398 uint32 bufferlen;
399 FILE *fp;
400
401 gtk_text_buffer_get_bounds( advanced_textbuffer, &start, &end );
402 text = gtk_text_iter_get_text( &start, &end );
403
404 fp = fopen( filename, "wb" );
405 if( fp == 0 )
406 {
407 GtkWidget *dialog;
408 char tmp_err[ERROR_OBJ_MSG_LEN];
409 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
410 dialog = gtk_message_dialog_new( GTK_WINDOW(advancedwin), GTK_DIALOG_DESTROY_WITH_PARENT,
411 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, tmp_err );
412 gtk_dialog_run( GTK_DIALOG(dialog) );
413 g_free(text);
414 return;
415 }
416
417 bufferlen = strlen(text);
418 if( fwrite( text, 1, bufferlen, fp ) != bufferlen )
419 {
420 GtkWidget *dialog;
421 char tmp_err[ERROR_OBJ_MSG_LEN];
422 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
423 dialog = gtk_message_dialog_new( GTK_WINDOW(advancedwin), GTK_DIALOG_DESTROY_WITH_PARENT,
424 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, tmp_err );
425 gtk_dialog_run( GTK_DIALOG(dialog) );
426 g_free(text);
427 return;
428 }
429 g_free(text);
430
431 if( fclose(fp) != 0 )
432 {
433 GtkWidget *dialog;
434 char tmp_err[ERROR_OBJ_MSG_LEN];
435 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't close file (%s)"), filename );
436 dialog = gtk_message_dialog_new( GTK_WINDOW(advancedwin), GTK_DIALOG_DESTROY_WITH_PARENT,
437 GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, tmp_err );
438 gtk_dialog_run( GTK_DIALOG(dialog) );
439 return;
440 }
441 }
442
advanced_file_save_as(void)443 void advanced_file_save_as(void)
444 {
445 GtkWidget *file_chooser;
446 GtkFileFilter *filter;
447
448 file_chooser = gtk_file_chooser_dialog_new( dialog_title_save_as, GTK_WINDOW(advancedwin),
449 GTK_FILE_CHOOSER_ACTION_SAVE,
450 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
451 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL );
452
453 filter = gtk_file_filter_new();
454 gtk_file_filter_add_pattern( filter, "*.ump" );
455 gtk_file_filter_set_name( filter, filter_ump_files );
456 gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(file_chooser), filter );
457
458 filter = gtk_file_filter_new();
459 gtk_file_filter_add_pattern(filter, "*");
460 gtk_file_filter_set_name(filter, filter_all_files);
461 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
462
463 if(gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT)
464 {
465 char *filename;
466
467 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
468
469 file_save(filename);
470
471 g_free(filename);
472 }
473
474 gtk_widget_destroy(file_chooser);
475 }
476
advancedwin_file_clear(void)477 void advancedwin_file_clear(void)
478 {
479 if(advancedwin == 0)
480 return;
481
482 char tmp_str[400];
483 snprintf(tmp_str,400,"\n%s %s\n\n Copyright (c) %s Mattias Hultgren\n",PRG_NAME,PRG_VERSION,PRG_DATE);
484 gtk_text_buffer_set_text(advanced_textbuffer,tmp_str,-1);
485
486 GtkTextIter iter;
487
488 gtk_text_buffer_get_end_iter( advanced_textbuffer, &iter);
489 gtk_text_buffer_insert( advanced_textbuffer, &iter, get_start_message(), -1);
490
491 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(advanced_textview),
492 gtk_text_buffer_get_mark(advanced_textbuffer, "the_end"));
493 }
advancedwin_translate(void)494 void advancedwin_translate(void)
495 {
496 if(advancedwin != 0)
497 {
498 GtkWidget *new_menu;
499
500 gtk_button_set_label( GTK_BUTTON(advanced_button), _("Calculate") );
501
502 if(( new_menu = advancedwin_build_menu()) == 0 )
503 return;
504
505 gtk_widget_destroy( advancedwin_menu );
506 advancedwin_menu = new_menu;
507
508 gtk_box_pack_start(GTK_BOX(advanced_vbox), advancedwin_menu, FALSE, FALSE, 0);
509 gtk_box_reorder_child( GTK_BOX(advanced_vbox), advancedwin_menu, 0 );
510
511 try{ degfix_changed(); }
512 catch(...) { }
513 }
514 }
advancedwin_close(void)515 void advancedwin_close(void)
516 {
517 if(advancedwin != 0)
518 {
519 gtk_widget_destroy(advancedwin);
520 advancedwin = 0;
521
522 open_windows &= ~ADVANCED_WIN;
523 if(open_windows == 0)
524 UMP_gtk_quit();
525 }
526 }
advanced_opt_radian(void)527 void advanced_opt_radian(void)
528 {
529 gtk_entry_set_text(GTK_ENTRY(GTK_BIN(advanced_combo)->child), "degfix = radian");
530 gtk_widget_activate(GTK_BIN(advanced_combo)->child);
531 }
advanced_opt_degree(void)532 void advanced_opt_degree(void)
533 {
534 gtk_entry_set_text(GTK_ENTRY(GTK_BIN(advanced_combo)->child), "degfix = degree");
535 gtk_widget_activate(GTK_BIN(advanced_combo)->child);
536 }
537