1 /* main.cpp is part of UDAV
2  * Copyright (C) 2007-2014 Alexey Balakin <mathgl.abalakin@gmail.ru>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 #include <ctype.h>
18 #include <errno.h>
19 #include <locale.h>
20 #include <getopt.h>
21 #include "mgllab.h"
22 #include <FL/Fl_Spinner.H>
23 #include <FL/Fl_Output.H>
24 #include <FL/Fl_Select_Browser.H>
25 #include <FL/Fl_Printer.H>
26 //-----------------------------------------------------------------------------
27 #ifndef MGL_DOC_DIR
28 #ifdef WIN32
29 #define MGL_DOC_DIR ""
30 #else
31 #define MGL_DOC_DIR "/usr/local/share/doc/mathgl/"
32 #endif
33 #endif
34 //-----------------------------------------------------------------------------
35 //int num_windows = 0, auto_exec=1, plastic_scheme=1, internal_font=0;
36 int num_windows = 0;
37 int auto_exec;
38 int exec_save;
39 int highlight;
40 int mouse_zoom;
41 int use_thr;
42 int complete_word;
43 int wndW=930, wndH=510, txtW=300;
44 std::string docdir;
45 std::string helpname;
46 std::string fontname;
47 int lang;
48 int scheme;
49 int dark;
50 std::string lastfiles[5];
51 Fl_Preferences pref(Fl_Preferences::USER,"abalakin","mgllab");
52 //-----------------------------------------------------------------------------
53 #define NUM_LOCALE	4
54 const char *sch[4]={"base","gtk+","plastic","gleam"};
55 const char *loc[]={"en_EN.UTF8",	"ru_RU.utf8",	"ru_RU.cp1251",	"es_ES.utf8",	""};
56 const char *hlp[]={"mgl_en.html#","mgl_ru.html#", "mgl_ru.html#", "mgl_en.html#",	""};
set_scheme_lang(int s,int l)57 void set_scheme_lang(int s, int l)
58 {
59 	if(s<0 || s>3)	s=1;
60 	if(l<0 || l>NUM_LOCALE-1)	l=1;
61 	mgl_textdomain(NULL,loc[l]);
62 	Fl::scheme(sch[s]);
63 	scheme = s;	lang = l;
64 #ifdef WIN32
65 	char sep = '\\';
66 #else
67 	char sep = '/';
68 #endif
69 	helpname = docdir+sep+hlp[l];
70 }
71 //-----------------------------------------------------------------------------
save_pref()72 void save_pref()
73 {
74 	pref.set("locale",lang);
75 	pref.set("scheme",scheme);
76 	pref.set("help_dir",docdir.c_str());
77 	pref.set("auto_exec",auto_exec);
78 	pref.set("exec_save",exec_save);
79 	pref.set("highlight",highlight);
80 	pref.set("mouse_zoom",mouse_zoom);
81 	pref.set("use_thr", use_thr);
82 	pref.set("font_kind",font_kind);
83 	pref.set("font_size",font_size);
84 	pref.set("complete_word",complete_word);
85 	pref.set("font_name",fontname.c_str());
86 	pref.set("fname1",lastfiles[0].c_str());
87 	pref.set("fname2",lastfiles[1].c_str());
88 	pref.set("fname3",lastfiles[2].c_str());
89 	pref.set("fname4",lastfiles[3].c_str());
90 	pref.set("fname5",lastfiles[4].c_str());
91 
92 	pref.set("wnd_width", wndW);
93 	pref.set("wnd_height",wndH);
94 	pref.set("txt_width", txtW);
95 	pref.set("dark",dark);
96 }
97 //-----------------------------------------------------------------------------
load_pref(ScriptWindow * w)98 void load_pref(ScriptWindow *w)
99 {
100 	static char *s=0;
101 	pref.get("locale",lang,1);
102 	pref.get("scheme",scheme,2);
103 	pref.get("help_dir",s,MGL_DOC_DIR);
104 	if(s)	{	docdir=s;	free(s);	}
105 	pref.get("auto_exec",auto_exec,1);
106 	pref.get("exec_save",exec_save,1);
107 	pref.get("highlight",highlight,1);
108 	pref.get("mouse_zoom",mouse_zoom,0);
109 	pref.get("use_thr",use_thr,1);
110 	pref.get("complete_word",complete_word,1);
111 	pref.get("font_kind",font_kind,1);
112 	pref.get("font_size",font_size,14);
113 	pref.get("dark", dark,0);
114 	set_style(font_kind, font_size,dark);
115 	pref.get("font_name",s,"");
116 	if(s)	{	fontname=s;	free(s);	}
117 
118 	pref.get("wnd_width", wndW,930);
119 	pref.get("wnd_height",wndH,510);
120 	pref.get("txt_width", txtW,300);
121 
122 	pref.get("fname1",s,"");	if(s)	{	lastfiles[0]=s;	free(s);	}
123 	pref.get("fname2",s,"");	if(s)	{	lastfiles[1]=s;	free(s);	}
124 	pref.get("fname3",s,"");	if(s)	{	lastfiles[2]=s;	free(s);	}
125 	pref.get("fname4",s,"");	if(s)	{	lastfiles[3]=s;	free(s);	}
126 	pref.get("fname5",s,"");	if(s)	{	lastfiles[4]=s;	free(s);	}
127 	set_scheme_lang(scheme,lang);	// NOTE: must be after setting docdir
128 	if(w && w->graph)
129 	{
130 		w->graph->FMGL->use_pthr = use_thr;
131 		mgl_load_font(w->graph->get_graph(),fontname.c_str(),NULL);
132 		example_cb(NULL, w);
133 		w->graph->parent()->show();
134 	}
135 }
136 //-----------------------------------------------------------------------------
set_title(Fl_Window * w)137 void set_title(Fl_Window* w)
138 {
139 	static std::string title;
140 	if (filename.empty()) title=_("Untitled");
141 	else
142 	{
143 		size_t sep = filename.find_last_of('/');
144 #ifdef WIN32
145 		if(sep==std::string::npos)
146 			sep = filename.find_last_of('\\');
147 #endif
148 		if(sep!=std::string::npos)	title = filename.substr(sep+1);
149 		else	title = filename;
150 	}
151 	if(changed)	title += " *";
152 	title = title + " - mgllab";
153 	w->label(title.c_str());
154 }
155 //-----------------------------------------------------------------------------
close_dlg_cb(Fl_Widget *,void * v)156 void close_dlg_cb(Fl_Widget *, void *v)	{	((Fl_Window *)v)->hide();	}
157 //-----------------------------------------------------------------------------
158 //-----------------------------------------------------------------------------
new_cb(Fl_Widget *,void *)159 void new_cb(Fl_Widget*, void*)
160 {
161 	if (!check_save()) return;
162 	filename[0] = '\0';
163 	textbuf->select(0, textbuf->length());
164 	textbuf->remove_selection();
165 	changed = 0;
166 	textbuf->call_modify_callbacks();
167 }
168 //-----------------------------------------------------------------------------
open_cb(Fl_Widget *,void * v)169 void open_cb(Fl_Widget*, void *v)
170 {
171 	if (!check_save()) return;
172 	const char *newfile = mgl_file_chooser(_("Open File?"),
173 		_("MGL files \t*.mgl\nDAT files \t*.{dat,csv}"));
174 	if(newfile != NULL)
175 	{
176 		ScriptWindow* e = (ScriptWindow*)v;
177 		load_file(newfile, -1,e);
178 		if(auto_exec)	e->graph->update();
179 	}
180 }
181 //-----------------------------------------------------------------------------
close_cb(Fl_Widget *,void * v)182 void close_cb(Fl_Widget*, void* v)
183 {
184 	Fl_Window* w = (Fl_Window*)v;
185 	if (num_windows == 1 && !check_save())	return;
186 
187 	w->hide();
188 	textbuf->remove_modify_callback(changed_cb, w);
189 	ScriptWindow *wnd = dynamic_cast<ScriptWindow*>(w);
190 	if(wnd)
191 	{
192 		wndW = wnd->w();
193 		wndH = wnd->h();
194 		txtW = wnd->editor->w();
195 		save_pref();
196 	}
197 	delete w;
198 	num_windows--;
199 	if (!num_windows) exit(0);
200 }
201 //-----------------------------------------------------------------------------
quit_cb(Fl_Widget *,void *)202 void quit_cb(Fl_Widget*, void*)
203 {
204 	if (changed && !check_save())	return;
205 	exit(0);
206 }
207 //-----------------------------------------------------------------------------
save_cb(Fl_Widget * w,void * v)208 void save_cb(Fl_Widget*w, void*v)
209 {
210 	if(filename.empty())	{	saveas_cb(w,v);	return;	}	// No filename - get one!
211 	else save_file(filename.c_str(),(ScriptWindow*)v);
212 }
213 //-----------------------------------------------------------------------------
saveas_cb(Fl_Widget *,void * v)214 void saveas_cb(Fl_Widget*, void *v)
215 {
216 	const char *newfile;
217 	char *fname=0;
218 	while(1)
219 	{
220 		newfile = mgl_file_chooser(_("Save File As?"), _("MGL files \t*.mgl"), true);
221 		if(!newfile || !newfile[0])	break;
222 		if(!strchr(newfile,'.'))
223 		{
224 			if(fname)	delete []fname;
225 			fname = new char[strlen(newfile)+5];
226 			strcpy(fname,newfile);	strcat(fname,".mgl");
227 			newfile = fname;
228 		}
229 		FILE *fp = fl_fopen(newfile,"r");
230 		if(fp)
231 		{
232 			fclose(fp);
233 			if(fl_choice(_("File exist. Overwrite it?"),0,_("No"),_(" Yes "))==2)
234 				break;
235 		}
236 		else	break;
237 	}
238 	if (newfile != NULL)	save_file(newfile, (ScriptWindow*)v);
239 	if(fname)	delete []fname;
240 }
241 //-----------------------------------------------------------------------------
242 ScriptWindow *new_view();
243 //void view_cb(Fl_Widget*, void*)
244 //{	Fl_Window* w = new_view();	w->show();	}
245 //-----------------------------------------------------------------------------
246 // void hint_cb(Fl_Widget*, void*)	{}
lastfile1_cb(Fl_Widget *,void * v)247 void lastfile1_cb(Fl_Widget*, void *v)
248 {	if (!check_save()) return;
249 	load_file(lastfiles[0].c_str(),-1,(ScriptWindow*)v);	}
lastfile2_cb(Fl_Widget *,void * v)250 void lastfile2_cb(Fl_Widget*, void *v)
251 {	if (!check_save()) return;
252 	load_file(lastfiles[1].c_str(),-1,(ScriptWindow*)v);	}
lastfile3_cb(Fl_Widget *,void * v)253 void lastfile3_cb(Fl_Widget*, void *v)
254 {	if (!check_save()) return;
255 	load_file(lastfiles[2].c_str(),-1,(ScriptWindow*)v);	}
lastfile4_cb(Fl_Widget *,void * v)256 void lastfile4_cb(Fl_Widget*, void *v)
257 {	if (!check_save()) return;
258 	load_file(lastfiles[3].c_str(),-1,(ScriptWindow*)v);	}
lastfile5_cb(Fl_Widget *,void * v)259 void lastfile5_cb(Fl_Widget*, void *v)
260 {	if (!check_save()) return;
261 	load_file(lastfiles[4].c_str(),-1,(ScriptWindow*)v);	}
262 //-----------------------------------------------------------------------------
print_plot_cb(Fl_Widget *,void * v)263 void print_plot_cb(Fl_Widget*,void *v)
264 {
265 	ScriptWindow *w = (ScriptWindow*)v;
266 	Fl_Printer *p = new Fl_Printer;
267 	if(!p->start_job(1) && !p->start_page())
268 	{
269 		int wp,hp, ww=w->graph->FMGL->w(), hh=w->graph->FMGL->h();
270 		p->printable_rect(&wp,&hp);
271 		double s=1, sw=double(wp)/ww, sh=double(hp)/hh;
272 		if(sw<s)	s=sw;
273 		if(sh<s)	s=sh;
274 //		if(sw<sh)	p->rotate(90);	// TODO add rotation ???
275 		p->scale(s,s);
276 		p->print_widget(w->graph->FMGL);
277 		p->end_page();		p->end_job();
278 	}
279 	delete p;
280 }
281 //-----------------------------------------------------------------------------
282 Fl_Menu_Item menuitems[] = {
283 	{_("File"), 0, 0, 0, FL_SUBMENU},
284 		{_("New script"), 0, new_cb},
285 		{_("Open file ..."), FL_CTRL+'o', open_cb},
286 		{_("Save file"), FL_CTRL+'s', save_cb},
287 		{_("Save as ..."), 0, saveas_cb, 0, FL_MENU_DIVIDER},
288 		{_("Print plot"), 0, print_plot_cb, 0, FL_MENU_DIVIDER},
289 		{_("Recent files"), 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER},
290 			{"1.", 0, lastfile1_cb},
291 			{"2.", 0, lastfile2_cb},
292 			{"3.", 0, lastfile3_cb},
293 			{"4.", 0, lastfile4_cb},
294 			{"5.", 0, lastfile5_cb},
295 			{0},
296 		{_("Exit"), 0, quit_cb},
297 		{0},
298 	{_("Edit"), 0, 0, 0, FL_SUBMENU},
299 		{_("Undo"), FL_CTRL+'z', undo_cb},
300 		{_("Cut text"), FL_CTRL+'x', cut_cb},
301 		{_("Copy text"), FL_CTRL+'c', copy_cb},
302 		{_("Paste text"), FL_CTRL+'v', paste_cb},
303 		{_("Select all"), FL_CTRL+'a', select_all_cb, 0, FL_MENU_DIVIDER},
304 		{_("Hidden plots"), FL_CTRL+'d', hide_cb},
305 		{_("Show lines"), FL_CTRL+FL_SHIFT+'d', unhide_cb, 0, FL_MENU_DIVIDER},
306 		{_("Find|Replace"), FL_CTRL+'f', find_dlg_cb},
307 		{_("Find next"), FL_F+3, find_next_cb, 0, FL_MENU_DIVIDER},
308 		{_("Insert"), 0, 0, 0, FL_SUBMENU},
309 			{_("File path"), FL_META+'p', ins_fname_cb},
310 			{_("Folder path"), 0, ins_path_cb},
311 			{_("Command"), FL_META+'c', newcmd_dlg_cb},
312 			{_("Inplot"), FL_META+'i', inplot_dlg_cb},
313 			{_("Fitted formula"), FL_META+'f', ins_fits_cb},
314 			{_("Manual primitives"), 0, ins_prim_cb},
315 			{_("Plot style"), 0, style_dlg_cb},
316 			{_("Options"), FL_META+'o', option_dlg_cb},
317 			{0},
318 	// TODO{_("Selection"), 0,  0, 0, FL_SUBMENU|FL_MENU_DIVIDER},
319 		// TODO{_("Hide"), 0,  0},
320 		// TODO{_("Delete"), 0,  0},
321 		// TODO{_("Move up"), 0,  0},
322 		// TODO{_("Move down"), 0,  0},
323 		// TODO{_("Show hidden"), FL_F+8,  0, 0, FL_MENU_TOGGLE},
324 		{0},
325 	{_("Graphics"), 0, 0, 0, FL_SUBMENU},
326 		{0},
327 	{_("Setup"), 0, 0, 0, FL_SUBMENU},
328 		{_("Properties"), 0, prop_dlg_cb},
329 		{_("Set arguments"), 0, args_dlg_cb},
330 		{_("Setup animation"), 0, animate_dlg_cb},
331 		{_("Plot setup"), FL_META+'g', setup_dlg_cb, 0, FL_MENU_DIVIDER},
332 		{_("Calculator"), FL_F+4, calc_dlg_cb},
333 		{_("Messages"), FL_F+2, message_cb},
334 		{0},
335 	{_("Help"), 0, 0, 0, FL_SUBMENU},
336 		{_("Help"), FL_F+1, help_cb},
337 		{_("Hints"), 0, hint_dlg_cb},
338 		{_("About"), 0, about_cb},
339 		{_("Icon list"), 0, iconlist_cb},	// TODO remove before release
340 		{0},
341 	{0}
342 };
343 //-----------------------------------------------------------------------------
mem_upd_cb(Fl_Widget *,void * v)344 void mem_upd_cb(Fl_Widget *, void *v)
345 {	((ScriptWindow*)v)->mem_init();	}
346 //-----------------------------------------------------------------------------
347 extern Fl_RGB_Image img_udav;
new_view()348 ScriptWindow *new_view()
349 {
350 	Fl_Group *gg;
351 	ScriptWindow *w = new ScriptWindow(wndW, wndH, _("Untitled - mgllab"));
352 	w->begin();
353 	w->menu = new Fl_Menu_Bar(0, 0, wndW, 30);
354 	w->menu->copy(menuitems, w);
355 	w->label(_("Untitled - mgllab"));
356 
357 	Fl_Tile *t = new Fl_Tile(0,30,wndW,wndH-55);
358 	add_editor(w, txtW, wndH);
359 
360 	w->rtab = new Fl_Tabs(txtW,30,wndW-txtW,wndH-55,0);
361 	w->gplot = new Fl_Group(txtW,30,wndW-txtW,wndH-80,_("Canvas"));
362 	w->graph = new Fl_MGLView(txtW,30,wndW-txtW,wndH-80,_("Canvas"));
363 	w->gplot->resizable(w->graph);	w->gplot->end();	w->graph->adjust();
364 	w->ghelp = new Fl_Group(txtW,30,wndW-txtW,wndH-80,_("Help"));
365 	add_help(w, txtW, wndW, wndH);	w->ghelp->end();	w->ghelp->hide();
366 	gg = new Fl_Group(txtW,30,wndW-txtW,wndH-80,_("Memory"));	gg->hide();
367 	add_mem(w, txtW, wndW, wndH);		gg->end();
368 	w->rtab->end();
369 
370 //	w->status = new Fl_Output(0,485,wndW,25);
371 	w->status = new Fl_Box(0,wndH-25,wndW,25);	w->status->box(FL_ENGRAVED_BOX);
372 	w->status->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
373 	w->set_status(_("Ready"));
374 	w->draw = new Fl_MGL(w->graph);	w->draw->e = w;
375 	mgl_makemenu_fltk(w->menu, w->graph);
376 	w->menu->add(_("Graphics/Primitive"), FL_CTRL+'m', prim_dlg_cb, w);
377 	w->menu->add(_("Graphics/Animation/Setup animation"), 0, animate_dlg_cb, w);
378 	int index = w->menu->find_index(_("Graphics/Pause calc"));
379 	if(index>=0)	w->menu->remove(index);
380 //	m->add(_("Graphics/Pause calc"), "^t", mgl_pause_cb, w, FL_MENU_TOGGLE);
381 
382 
383 	t->end();	w->end();	w->resizable(t);
384 	w->rtab->callback(mem_upd_cb, w);
385 	w->callback(close_cb, w);	w->icon(&img_udav);
386 	num_windows++;	return w;
387 }
388 //-----------------------------------------------------------------------------
389 void argument_set(int n, const char *s);
main(int argc,char ** argv)390 int main(int argc, char **argv)
391 {
392 //	Fl::lock();
393 	mgl_ask_func = mgl_ask_fltk;
394 	mgl_progress_func = mgl_progress_fltk;
395 	load_pref(NULL);
396 
397 	textbuf = new Fl_Text_Buffer;
398 	style_init();
399 	textbuf->tab_distance(4);
400 	ScriptWindow *w = new_view();
401 	Fl::visual(FL_DOUBLE|FL_RGB);
402 	load_pref(w);
403 	int ir = w->menu->find_index(_("File/Recent files"));
404 	if(ir<0)	ir = 6;
405 	w->menu->replace(ir+1, lastfiles[0].c_str());
406 	w->menu->replace(ir+2, lastfiles[1].c_str());
407 	w->menu->replace(ir+3, lastfiles[2].c_str());
408 	w->menu->replace(ir+4, lastfiles[3].c_str());
409 	w->menu->replace(ir+5, lastfiles[4].c_str());
410 	int sh;	pref.get("show_hint",sh,1);
411 	if(sh)	hint_dlg_cb(0,0);
412 
413 	std::string fname;
414 	while(1)
415 	{
416 		char ch = getopt(argc, argv, "1:2:3:4:5:6:7:8:9:ho:L:");
417 		if(ch>='1' && ch<='9')	argument_set(ch-'0', optarg);
418 		else if(ch=='L')
419 		{	setlocale(LC_CTYPE, optarg);	setlocale(LC_NUMERIC, "C");	}
420 		else if(ch=='h')
421 		{
422 			printf(_("mgllab draw mgl script interactively.\nCurrent version is 2.%g\n"),MGL_VER2);
423 			printf(_("Usage:\tmgllab [parameter(s)] scriptfile\n"));
424 			printf(_("\t-1 str       set str as argument $1 for script\n"
425 					"\t...          ...\n"
426 					"\t-9 str       set str as argument $9 for script\n"
427 					"\t-L loc       set locale to loc\n"
428 //					"\t-            get script from standard input\n"
429 					"\t-h           print this message\n") );
430 			return 0;
431 		}
432 		// NOTE: I will not parse stdin here
433 		else if(ch==-1)
434 		{	if(optind<argc)	fname = argv[optind];
435 			break;	}
436 	}
437 
438 	w->show(1, argv);
439 	if(!fname.empty() && fname[0]!='-')
440 	{
441 		load_file(fname.c_str(), -1,w);
442 		if(auto_exec)	w->graph->update();
443 	}
444 	return Fl::run();
445 }
446 //-----------------------------------------------------------------------------
447 void cb_filech(Fl_Widget*, void *v);
448 class PropDlg : public GeneralDlg
449 {
450 	friend void cb_filech(Fl_Widget*, void *v);
451 	Fl_Choice *fkind;
452 	Fl_Spinner *fsize;
453 	Fl_File_Input *help_path;
454 	Fl_File_Input *font_path;
455 	Fl_Check_Button *auto_exec_w;
456 	Fl_Check_Button *exec_save_w;
457 	Fl_Check_Button *complete_w;
458 	Fl_Check_Button *highlight_w;
459 	Fl_Check_Button *mouse_zoom_w;
460 	Fl_Check_Button *use_thr_w;
461 	Fl_Check_Button *dark_w;
462 	Fl_Choice *lang_w;
463 	Fl_Choice *scheme_w;
464 public:
PropDlg()465 	PropDlg() : GeneralDlg()
466 	{
467 		Fl_Button *o;
468 		w = new Fl_Double_Window(340, 415, _("Properties"));
469 		w->align(Fl_Align(FL_ALIGN_CLIP|FL_ALIGN_INSIDE));
470 		fkind = new Fl_Choice(75, 10, 90, 25, _("Font kind"));
471 		fkind->add("Helvetica");	fkind->add("Courier");	fkind->add("Times");
472 		fsize = new Fl_Spinner(245, 10, 90, 25, _("Font size"));
473 		help_path = new Fl_File_Input(5, 55, 305, 35, _("Path for help files"));
474 		help_path->align(FL_ALIGN_TOP_LEFT);
475 		o = new Fl_Button(310, 65, 25, 25, "...");	o->callback(cb_filech, 0);
476 		font_path = new Fl_File_Input(5, 110, 305, 35, _("Path for MathGL font (without extension)"));
477 		font_path->align(FL_ALIGN_TOP_LEFT);
478 		o = new Fl_Button(310, 120, 25, 25, "...");	o->callback(cb_filech, (void *)1);
479 		auto_exec_w = new Fl_Check_Button(5, 145, 330, 25, _("Execute script after loading"));
480 		exec_save_w = new Fl_Check_Button(5, 170, 330, 25, _("Save file before redrawing"));
481 		complete_w = new Fl_Check_Button(5, 195, 330, 25, _("Enable keywords completion"));
482 		highlight_w = new Fl_Check_Button(5, 220, 330, 25, _("Highlight current object(s)"));
483 		mouse_zoom_w = new Fl_Check_Button(5, 245, 330, 25, _("Enable mouse wheel for zooming"));
484 		use_thr_w = new Fl_Check_Button(5, 270, 330, 25, _("Use multi-threading for drawing"));
485 		dark_w = new Fl_Check_Button(5, 295, 330, 25, _("Use dark color scheme"));
486 		lang_w = new Fl_Choice(160, 325, 175, 25, _("Language for mgllab"));
487 		for(long i=0;i<NUM_LOCALE;i++)	lang_w->add(loc[i]);
488 		scheme_w = new Fl_Choice(160, 355, 175, 25, _("Widget scheme"));
489 		scheme_w->add("base");	scheme_w->add("gtk+");	scheme_w->add("plastic");	scheme_w->add("gleam");
490 		o = new Fl_Button(85, 385, 75, 25, _("Cancel"));	o->callback(cb_dlg_cancel,this);
491 		o = new Fl_Return_Button(180, 385, 75, 25, _("OK"));	o->callback(cb_dlg_ok,this);
492 		w->set_modal();	w->end();
493 	}
init()494 	void init()
495 	{
496 		fkind->value(styletable[0].font/4);
497 		fsize->value(styletable[0].size);
498 		font_path->value(fontname.c_str());
499 		help_path->value(docdir.c_str());
500 		auto_exec_w->value(auto_exec);
501 		exec_save_w->value(exec_save);
502 		complete_w->value(complete_word);
503 		highlight_w->value(highlight);
504 		mouse_zoom_w->value(mouse_zoom);
505 		use_thr_w->value(use_thr);
506 		lang_w->value(lang);
507 		scheme_w->value(scheme);
508 		dark_w->value(dark);
509 	}
cb_ok()510 	void cb_ok()
511 	{
512 		auto_exec = auto_exec_w->value();
513 		exec_save = exec_save_w->value();
514 		highlight = highlight_w->value();
515 		mouse_zoom = mouse_zoom_w->value();
516 		complete_word = complete_w->value();
517 		use_thr = use_thr_w->value();
518 		docdir = help_path->value();
519 		fontname = font_path->value();
520 		dark = dark_w->value();
521 		set_style(fkind->value(),fsize->value(),dark);
522 		if(e->graph->get_graph())
523 			mgl_load_font(e->graph->get_graph(),fontname.c_str(),NULL);
524 		set_scheme_lang(scheme_w->value(),lang_w->value());	// NOTE: must be after setting docdir
525 		example_cb(NULL, e);	e->graph->parent()->show();
526 		save_pref();	hide();
527 	}
528 } prop_dlg;
529 //-----------------------------------------------------------------------------
cb_filech(Fl_Widget *,void * v)530 void cb_filech(Fl_Widget*, void *v)
531 {
532 	if(v)
533 	{
534 		const char *s = mgl_file_chooser(_("Font file name"), "MGL font files \t*.vfm*");
535 		if(s)
536 		{	std::string ss = s;
537 			size_t pos = ss.find(".vfm");
538 			if(pos!=std::string::npos)	ss = ss.substr(0,pos);
539 			prop_dlg.font_path->value(ss.c_str());	}
540 	}
541 	else
542 	{
543 		const char *s = mgl_dir_chooser(_("Folder for help files"), prop_dlg.help_path->value());
544 		if(s)	prop_dlg.help_path->value(s);
545 	}
546 }
prop_dlg_cb(Fl_Widget *,void * v)547 void prop_dlg_cb(Fl_Widget *, void *v)
548 {	prop_dlg.e = (ScriptWindow *)v;	prop_dlg.show();	}
549 //-----------------------------------------------------------------------------
550 void cb_calc_key(Fl_Widget *, void *v);
551 void cb_calc_ins(Fl_Widget *, void *);
552 void cb_calc_prev(Fl_Widget *, void *);
553 void cb_calc_edit(Fl_Widget *, void *);
554 void cb_calc_kind(Fl_Widget *, void *);
555 void cb_calc_func(Fl_Widget *, void *);
556 class CalcDlg : public GeneralDlg
557 {
558 public:
559 	Fl_Input *edit;
560 	Fl_Output *output;
561 	Fl_Browser *prev;
562 	Fl_Choice *kind;
563 	Fl_Choice *func;
CalcDlg()564 	CalcDlg() : GeneralDlg()
565 	{
566 		Fl_Button *o;	Fl_Group* g, *gg;
567 		w = new Fl_Double_Window(275, 275, _("Calculator"));
568 		g = new Fl_Group(5, 5, 265, 25);
569 		edit = new Fl_Input(5, 5, 240, 25);	//edit->callback(cb_calc_edit);
570 		o = new Fl_Return_Button(245, 5, 25, 25, "@>");
571 		o->callback(cb_calc_edit);	g->end();	g->resizable(edit);
572 		g = new Fl_Group(5, 35, 265, 25);
573 		output = new Fl_Output(30, 35, 145, 25, "@->");
574 		o = new Fl_Button(180, 35, 90, 25, _("to script"));
575 		o->callback(cb_calc_ins);	g->end();	g->resizable(output);
576 		prev = new Fl_Select_Browser(5, 80, 265, 70, _("Previous expressions"));
577 		prev->align(FL_ALIGN_TOP_LEFT);	prev->callback(cb_calc_prev);
578 		static int widths[] = { 200, 65, 0 };  // widths for each column
579 		prev->column_widths(widths);	prev->column_char('\t');
580 		gg = new Fl_Group(5, 155, 265, 115);
581 			o = new Fl_Button(5, 155, 25, 25, "7");		o->callback(cb_calc_key,o);
582 			o = new Fl_Button(35, 155, 25, 25, "8");	o->callback(cb_calc_key,o);
583 			o = new Fl_Button(65, 155, 25, 25, "9");	o->callback(cb_calc_key,o);
584 			o = new Fl_Button(95, 155, 25, 25, "+");	o->callback(cb_calc_key,o);
585 			o = new Fl_Button(125, 155, 25, 25, "pi");	o->callback(cb_calc_key,o);
586 			o = new Fl_Button(5, 185, 25, 25, "4");		o->callback(cb_calc_key,o);
587 			o = new Fl_Button(35, 185, 25, 25, "5");	o->callback(cb_calc_key,o);
588 			o = new Fl_Button(65, 185, 25, 25, "6");	o->callback(cb_calc_key,o);
589 			o = new Fl_Button(95, 185, 25, 25, "-");	o->callback(cb_calc_key,o);
590 			o = new Fl_Button(125, 185, 25, 25, "^");	o->callback(cb_calc_key,o);
591 			o = new Fl_Button(5, 215, 25, 25, "1");		o->callback(cb_calc_key,o);
592 			o = new Fl_Button(35, 215, 25, 25, "2");	o->callback(cb_calc_key,o);
593 			o = new Fl_Button(65, 215, 25, 25, "3");	o->callback(cb_calc_key,o);
594 			o = new Fl_Button(95, 215, 25, 25, "*");	o->callback(cb_calc_key,o);
595 			o = new Fl_Button(125, 215, 25, 25, "(");	o->callback(cb_calc_key,o);
596 			o = new Fl_Button(5, 245, 25, 25, "0");		o->callback(cb_calc_key,o);
597 			o = new Fl_Button(35, 245, 25, 25, ".");	o->callback(cb_calc_key,o);
598 			o = new Fl_Button(65, 245, 25, 25, "E");	o->callback(cb_calc_key,o);
599 			o = new Fl_Button(95, 245, 25, 25, "/");	o->callback(cb_calc_key,o);
600 			o = new Fl_Button(125, 245, 25, 25, ")");	o->callback(cb_calc_key,o);
601 
602 			g = new Fl_Group(155, 175, 115, 95, _("Function"));
603 			kind = new Fl_Choice(160, 179, 105, 25);	kind->callback(cb_calc_kind);
604 			kind->add("Basic");	kind->add("Exp and log");	kind->add("Trigonometric");
605 			kind->add("Hyperbolic");	kind->add("Bessel");	kind->add("Elliptic");
606 			kind->add("Jacobi");	 kind->add("Airy and Gamma");
607 			kind->add("Exp-integrals"); kind->add("Special");	kind->value(0);
608 
609 			func = new Fl_Choice(160, 209, 105, 25);
610 			o = new Fl_Button(160, 239, 105, 25, _("Put function"));	o->callback(cb_calc_func);
611 			g->end();	g->box(FL_DOWN_BOX);
612 		gg->end();	gg->resizable(g);
613 
614 		w->end();	w->resizable(prev);
615 	}
eval()616 	void eval()
617 	{
618 		const char *eq = edit->value();
619 		mglData d = Parse->Calc(eq);
620 		result = mgl_str_num(d.a[0]);
621 		output->value(result.c_str());
622 		std::string buf = eq+('\t'+result);
623 		prev->insert(0,buf.c_str());
624 	}
set_kind()625 	void set_kind()
626 	{
627 		int val = kind->value();	func->clear();
628 		switch(val)
629 		{
630 		case 0:	// basic
631 			func->add("abs()");		func->add("sign()");	func->add("step()");	func->add("sqrt()");
632 			func->add("mod(,)");	func->add("arg(,)");	break;
633 		case 1:	// exp and logarithms
634 			func->add("exp()");		func->add("pow(,)");	func->add("ln()");		func->add("lg()");
635 			func->add("log(,)");	break;
636 		case 2:	// trigonometric
637 			func->add("sin()");		func->add("cos()");		func->add("tan()");		func->add("sinc()");
638 			func->add("asin()");	func->add("acos()");	func->add("atan()");	break;
639 		case 3:	// hyperbolic
640 			func->add("sinh()");	func->add("cosh()");	func->add("tanh()");	func->add("asinh()");
641 			func->add("acosh()");	func->add("atanh()");	break;
642 		case 4:	// bessel
643 			func->add("bessel_j(,)");	func->add("bessel_y(,)");	func->add("bessel_i(,)");	func->add("bessel_k(,)");	break;
644 		case 5:	// elliptic
645 			func->add("elliptic_e(,)");	func->add("elliptic_f(,)");	func->add("elliptic_ec()");	func->add("elliptic_kc()");	break;
646 		case 6:	// jacobi
647 			func->add("sn(,)");		func->add("cn(,)");		func->add("dn(,)");		func->add("sc(,)");
648 			func->add("dc(,)");		func->add("nc(,)");		func->add("cs(,)");		func->add("ds(,)");
649 			func->add("ns(,)");		func->add("sd(,)");		func->add("cd(,)");		func->add("nd(,)");	break;
650 		case 7:	// airy and gamma
651 			func->add("airy_ai()");	func->add("airy_bi()");	func->add("airy_dai()");func->add("airy_dbi()");
652 			func->add("gamma()");	func->add("psi()");		func->add("beta(,)");	break;
653 		case 8:	// exp integrals
654 			func->add("ci()");		func->add("si()");		func->add("ei()");		func->add("e1()");
655 			func->add("e2()");		func->add("ei3()");	break;
656 		case 9:	// special
657 			func->add("erf()");		func->add("z()");		func->add("legendre(,)");	func->add("dilog()");
658 			func->add("eta()");		func->add("zeta()");	func->add("w0()");		func->add("w1()");	break;
659 		}
660 //		func->value(0);
661 	}
662 } calc_dlg;
663 //-----------------------------------------------------------------------------
cb_calc_key(Fl_Widget *,void * v)664 void cb_calc_key(Fl_Widget *, void *v)
665 {	Fl_Button *o=(Fl_Button *)v;	calc_dlg.edit->insert(o->label());	}
cb_calc_ins(Fl_Widget *,void *)666 void cb_calc_ins(Fl_Widget *, void *)
667 {	if(calc_dlg.e)	calc_dlg.e->editor->insert(calc_dlg.output->value());	}
cb_calc_prev(Fl_Widget *,void *)668 void cb_calc_prev(Fl_Widget *, void *)
669 {
670 	const char *s = calc_dlg.prev->text(calc_dlg.prev->value());
671 	if(s && *s)
672 	{
673 		std::string ss(s);	size_t l=ss.length();
674 		for(size_t i=0;i<l;i++)	if(ss[i]=='\t')	ss[i]=0;
675 		calc_dlg.edit->value(ss.c_str());
676 	}
677 }
cb_calc_edit(Fl_Widget *,void *)678 void cb_calc_edit(Fl_Widget *, void *)	{	calc_dlg.eval();	}
cb_calc_kind(Fl_Widget *,void *)679 void cb_calc_kind(Fl_Widget *, void *)	{	calc_dlg.set_kind();	}
cb_calc_func(Fl_Widget *,void *)680 void cb_calc_func(Fl_Widget *, void *)
681 {	const char *s = calc_dlg.func->text();
682 	if(s && *s)	calc_dlg.edit->insert(s);	}
683 //-----------------------------------------------------------------------------
calc_dlg_cb(Fl_Widget *,void * v)684 void calc_dlg_cb(Fl_Widget *, void *v)
685 {	calc_dlg.e = (ScriptWindow *)v;	calc_dlg.show();	}
686 //-----------------------------------------------------------------------------
687