1 /* editor.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 #ifdef __MWERKS__
20 # define FL_DLL
21 #endif
22 #ifdef WIN32
23 #include <direct.h>
24 #else
25 #include <unistd.h>
26 #endif
27 #include "mgllab.h"
28 //-----------------------------------------------------------------------------
29 int changed = 0;
30 std::string filename;
31 Fl_Text_Buffer *textbuf = 0;
32 //-----------------------------------------------------------------------------
33 // Syntax highlighting
34 Fl_Text_Buffer *stylebuf = 0;
35 Fl_Text_Display::Style_Table_Entry styletable[10] = { // Style table
36 { FL_BLACK, FL_COURIER, 14, 0 }, // A - Plain
37 { FL_DARK_GREEN,FL_COURIER_ITALIC, 14, 0 }, // B - Line comments
38 { FL_BLUE, FL_COURIER, 14, 0 }, // C - Number
39 { FL_RED, FL_COURIER, 14, 0 }, // D - Strings
40 { FL_DARK_BLUE, FL_COURIER, 14, 0 }, // E - Usual command
41 { FL_DARK_CYAN, FL_COURIER, 14, 0 }, // F - Flow command
42 { FL_DARK_MAGENTA, FL_COURIER, 14, 0 }, // G - New-data command
43 { FL_DARK_RED, FL_COURIER, 14, 0 }, // H - Option
44 { FL_GRAY, FL_COURIER, 14, 0 }, // I - Inactive command
45 { FL_MAGENTA, FL_COURIER, 14, 0 } // J - Error line ???
46 };
47 int font_kind; ///< Editor font kind
48 int font_size; ///< Editor font size
49 //-----------------------------------------------------------------------------
set_style(int kind,int size,int fdark)50 void set_style(int kind, int size, int fdark)
51 {
52 Fl_Color c1[10]={FL_BLACK,FL_DARK_GREEN,FL_BLUE,FL_RED,FL_DARK_BLUE,FL_DARK_CYAN,FL_DARK_MAGENTA,FL_DARK_RED,FL_GRAY,FL_MAGENTA};
53 Fl_Color c2[10]={FL_WHITE,FL_GREEN,FL_CYAN,FL_YELLOW,FL_BLUE,FL_CYAN,FL_MAGENTA,FL_RED,FL_GRAY,FL_MAGENTA};
54 if(kind<0 || kind>2) kind = 1;
55 if(size<1) size = 14;
56 for(int i=0;i<10;i++) // set font for styles
57 { styletable[i].size = size; styletable[i].font = 4*kind; }
58 styletable[1].font = 4*kind+2;
59 font_kind = kind; font_size = size;
60 if(fdark) for(int i=0;i<10;i++) styletable[i].color = c2[i];
61 else for(int i=0;i<10;i++) styletable[i].color = c1[i];
62 }
63 //-----------------------------------------------------------------------------
is_sfx(const char * s)64 bool MGL_FUNC_PURE is_sfx(const char *s) // suffix
65 {
66 size_t i,n=strlen(s);
67 for(i=0;i<n && s[i]>='a';i++);
68 if(i==1 && s[0]=='a') return true;
69 if(i==2 && strchr("nmawsk",s[0]) && strchr("axyz",s[1])) return true;
70 if(i==3 && (!strncmp("fst",s,3) || !strncmp("lst",s,3) || !strncmp("max",s,3) ||
71 !strncmp("min",s,3) || !strncmp("sum",s,3)))
72 return true;
73 if(i==3 && s[0]=='m' && strchr("xyz",s[1]) && strchr("fl",s[2])) return true;
74 return false;
75 // char *t = new char[i+1]; memcpy(t,s,i*sizeof(char)); t[i]=0;
76 }
77 //-----------------------------------------------------------------------------
is_opt(const char * s)78 bool MGL_FUNC_PURE is_opt(const char *s) // option
79 {
80 const char *o[13]={"xrange","yrange","zrange","crange","alpha",
81 "cut","value","meshnum","size","legend",
82 "ambient","diffuse","light"};
83 int l[13] = {6,6,6,6,5, 3,5,7,4,6, 7,7,5};
84 for(size_t i=0;i<13;i++) if(!strncmp(o[i],s,l[i]) && s[l[i]]<=' ') return true;
85 return false;
86 }
87 //-----------------------------------------------------------------------------
is_num(const char * s)88 bool MGL_FUNC_PURE is_num(const char *s) // number
89 {
90 size_t n=strlen(s);
91 // if(s[0]==':' && (s[1]<=' ' || s[1]==';')) return true;
92 if(s[0]<=' ' || s[0]==';' || s[0]==':') return false;
93 if(n>=2 && (s[2]<=' ' || s[2]==';' || s[2]==':'))
94 {
95 if(!strncmp("pi",s,2)) return true;
96 if(!strncmp("on",s,2)) return true;
97 }
98 if(n>=3 && (s[3]<=' ' || s[3]==';' || s[3]==':'))
99 {
100 if(!strncmp("off",s,3)) return true;
101 if(!strncmp("nan",s,3)) return true;
102 if(!strncmp("inf",s,3)) return true;
103 if(!strncmp("all",s,3)) return true;
104 }
105 for(size_t i=0;i<n;i++)
106 {
107 if(s[i]<=' ' || s[i]==';' || s[i]==':') break;
108 if(!strchr("+-.eE0123456789",s[i])) return false;
109 }
110 return true;
111 // char *t = new char[i+1]; memcpy(t,s,i*sizeof(char)); t[i]=0;
112 }
113 //-----------------------------------------------------------------------------
is_cmd(const char * s)114 char is_cmd(const char *s) // command
115 {
116 long i,n=strlen(s)+1;
117 char res=0, *w=new char[n]; strcpy(w,s);
118 for(i=0;i<n;i++) if(!isalnum(s[i])) w[i]=0;
119 int rts = Parse->CmdType(w);
120 if(rts==5) res = 'G';
121 else if(rts==7) res = 'F';
122 else if(rts) res = 'E';
123 delete []w; return res;
124 }
125 //-----------------------------------------------------------------------------
126 // Parse text and produce style data.
style_parse(const char * text,char * style,int)127 void style_parse(const char *text, char *style, int /*length*/)
128 {
129 size_t n=strlen(text);
130 bool nl=true;
131 // Style letters:
132 // A - Plain
133 // B - Line comments
134 // C - Number
135 // D - Strings
136 // E - Usual command
137 // F - Flow command
138 // G - New data command
139 // H - Option
140
141 for(size_t i=0;i<n;i++)
142 {
143 char ch = text[i], r; style[i] = 'A';
144 if(ch=='#') // comment
145 for(;i<n && text[i]!='\n';i++) style[i]='B';
146 else if(ch=='\'') // string
147 {
148 style[i]='D'; i++;
149 for(;i<n && text[i]!='\n' && text[i]!='\'';i++) style[i]='D';
150 style[i]='D';
151 }
152 else if(ch=='\n' || ch==':') { nl=true; continue; }
153 else if(nl && (r=is_cmd(text+i)) ) // command name
154 { for(;i<n && isalnum(text[i]);i++) style[i]=r; i--; }
155 else if(!nl && is_opt(text+i)) // option
156 { for(;i<n && isalpha(text[i]);i++) style[i]='H'; i--; }
157 else if(!nl && is_num(text+i)) // number
158 {
159 for(;i<n && strchr("+-.eE0123456789pionaf",text[i]);i++) style[i]='C';
160 i--;
161 }
162 else if(ch=='.' && is_sfx(text+i+1)) // option (suffix)
163 {
164 style[i]='H'; i++;
165 for(;i<n && isalpha(text[i]);i++) style[i]='H';
166 }
167 else if(ch=='.' || (ch>='0' && ch<='9'))
168 { style[i]='C'; if(text[i+1]=='e' || text[i+1]=='E') style[i+1]='C'; }
169 nl = false;
170 }
171 }
172 //-----------------------------------------------------------------------------
173 // Initialize the style buffer
style_init()174 void style_init()
175 {
176 long len = textbuf->length();
177 char *style = new char[len + 1];
178 char *text = textbuf->text();
179 memset(style, 'A', len); style[len] = '\0';
180 if(!stylebuf) stylebuf = new Fl_Text_Buffer(len);
181 style_parse(text, style, len);
182 stylebuf->text(style);
183 delete []style; free(text);
184 }
185 //-----------------------------------------------------------------------------
186 // Update unfinished styles.
style_unfinished_cb(int,void *)187 void style_unfinished_cb(int, void*) {}
188 //-----------------------------------------------------------------------------
189 // Update the style buffer...
style_update(int pos,int nInserted,int nDeleted,int,const char *,void * cbArg)190 void style_update(int pos, int nInserted, int nDeleted, int /*nRestyled*/, const char */*deletedText*/, void *cbArg)
191 {
192 long start, end; // Start and end of text
193 char last, // Last style on line
194 *style, // Style data
195 *text; // Text data
196
197 // If this is just a selection change, just unselect the style buffer...
198 if (nInserted == 0 && nDeleted == 0) { stylebuf->unselect(); return; }
199 // Track changes in the text buffer...
200 if (nInserted > 0)
201 {
202 // Insert characters into the style buffer...
203 style = new char[nInserted + 1];
204 memset(style, 'A', nInserted);
205 style[nInserted] = '\0';
206
207 stylebuf->replace(pos, pos + nDeleted, style);
208 delete[] style;
209 }
210 else // Just delete characters in the style buffer...
211 stylebuf->remove(pos, pos + nDeleted);
212 // Select the area that was just updated to avoid unnecessary callbacks...
213 stylebuf->select(pos, pos + nInserted - nDeleted);
214 // Re-parse the changed region; we do this by parsing from the
215 // beginning of the previous line of the changed region to the end of
216 // the line of the changed region... Then we check the last
217 // style character and keep updating if we have a multi-line
218 // comment character...
219 start = textbuf->line_start(pos);
220 end = textbuf->line_end(pos + nInserted);
221 text = textbuf->text_range(start, end);
222 style = stylebuf->text_range(start, end);
223 if (start==end) last = 0;
224 else last = style[end-start-1];
225 style_parse(text, style, end - start);
226 stylebuf->replace(start, end, style);
227 ((Fl_Text_Editor *)cbArg)->redisplay_range(start, end);
228
229 if (start==end || last != style[end-start-1])
230 {
231 // Either the user deleted some text, or the last character on
232 // the line changed styles, so reparse the remainder of the buffer...
233 free(text); free(style);
234 end = textbuf->length();
235 text = textbuf->text_range(start, end);
236 style = stylebuf->text_range(start, end);
237 style_parse(text, style, end - start);
238 stylebuf->replace(start, end, style);
239 ((Fl_Text_Editor *)cbArg)->redisplay_range(start, end);
240 }
241 free(text); free(style);
242 }
243 //-----------------------------------------------------------------------------
ScriptWindow(int w,int h,const char * t)244 ScriptWindow::ScriptWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t)
245 { editor = 0; }
246 //-----------------------------------------------------------------------------
set_path(char * buf)247 void set_path(char *buf)
248 {
249 #ifdef WIN32
250 char sep='\\';
251 #else
252 char sep='/';
253 #endif
254 for(long i=strlen(buf)-1;i>=0;i--) if(buf[i]==sep)
255 { buf[i]=0; break; }
256 if(!chdir(buf)) printf("chdir to '%s'\n",buf);
257 }
258 //-----------------------------------------------------------------------------
add_filename(const char * fname,ScriptWindow * e)259 void add_filename(const char *fname, ScriptWindow *e)
260 {
261 static char buf[FL_PATH_MAX];
262 fl_filename_absolute(buf, FL_PATH_MAX, fname); fname=buf;
263 if(!fname || !fname[0] || lastfiles[0]==fname)
264 { set_path(buf); return; }
265 pref.set("last_file",fname);
266 int ii=4;
267 for(int i=1;i<5;i++)
268 if(lastfiles[i]==fname) { ii=i; break; }
269 for(int i=ii;i>0;i--) lastfiles[i]=lastfiles[i-1];
270 lastfiles[0]=fname;
271 int ir = e->menu->find_index(_("File/Recent files"));
272 if(ir<0) ir = 6;
273 e->menu->replace(ir+1, lastfiles[0].c_str());
274 e->menu->replace(ir+2, lastfiles[1].c_str());
275 e->menu->replace(ir+3, lastfiles[2].c_str());
276 e->menu->replace(ir+4, lastfiles[3].c_str());
277 e->menu->replace(ir+5, lastfiles[4].c_str());
278 set_path(buf); save_pref();
279 }
280 //-----------------------------------------------------------------------------
check_save(void)281 int check_save(void)
282 {
283 if (!changed) return 1;
284 int r = fl_choice(_("The current file has not been saved.\n"
285 "Would you like to save it now?"),
286 _("Cancel"), _("Save"), _("Don't Save"));
287 if(r==1) { save_cb(0,0); return !changed; } // Save the file...
288 return (r==2) ? 1 : 0;
289 }
290 //-----------------------------------------------------------------------------
data_file(const char * fn)291 void data_file(const char *fn)
292 {
293 static int num=0;
294 static char name[32], res[256];
295 snprintf(name,32,"mgl_%d",num); num++;
296 mglDataA *v = Parse->AddVar(name);
297 mglData *d = dynamic_cast<mglData*>(v);
298 mglDataC *c = dynamic_cast<mglDataC*>(v);
299 if(d)
300 {
301 d->Read(fn);
302 if(d->nz>1)
303 snprintf(res,256,"#read %s '%s'\nrotate 40 60\ncrange %s\nbox\nsurf3 %s\n", name, fn, name, name);
304 else if(d->ny>1)
305 snprintf(res,256,"#read %s '%s'\nrotate 40 60\ncrange %s\nzrange %s\nbox\nsurf %s\n", name, fn, name, name, name);
306 else
307 snprintf(res,256,"#read %s '%s'\nyrange %s\nbox\nplot %s\n", name, fn, name, name);
308 textbuf->text(res);
309 }
310 else if(c)
311 {
312 c->Read(fn);
313 if(c->nz>1)
314 snprintf(res,256,"#read %s '%s'\nrotate 40 60\ncrange %s\nbox\nsurf3 %s\n", name, fn, name, name);
315 else if(c->ny>1)
316 snprintf(res,256,"#read %s '%s'\nrotate 40 60\ncrange %s\nzrange %s\nbox\nsurf %s\n", name, fn, name, name, name);
317 else
318 snprintf(res,256,"#read %s '%s'\nyrange %s\nbox\nplot %s\n", name, fn, name, name);
319 textbuf->text(res);
320 }
321 }
322 //-----------------------------------------------------------------------------
323 int loading = 0;
load_file(const char * newfile,int ipos,ScriptWindow * e)324 void load_file(const char *newfile, int ipos, ScriptWindow *e)
325 {
326 long len = strlen(newfile);
327 if(ipos==-1 && (!strcmp(newfile+len-4,".dat") || !strcmp(newfile+len-4,".csv")))
328 {
329 data_file(newfile);
330 filename = newfile; filename += ".mgl";
331 add_filename(filename.c_str(),e);
332 }
333 else
334 {
335 loading = 1;
336 int insert = (ipos != -1);
337 changed = insert;
338 if(!insert) filename="";
339 long r;
340 if(!insert) r = textbuf->loadfile(newfile);
341 else r = textbuf->insertfile(newfile, ipos);
342
343 char *t = textbuf->text();
344 #ifndef WIN32
345 size_t i,l=strlen(t);
346 for(i=0;i<l;i++) if(t[i]=='\r') t[i]=' ';
347 textbuf->text(t);
348 #endif
349 fill_animate(t, e->draw); free(t);
350
351 if (r)
352 fl_alert(_("Error reading from file \'%s\':\n%s."), newfile, strerror(errno));
353 else if(!insert)
354 { filename = newfile; add_filename(filename.c_str(),e); }
355 loading = 0;
356 textbuf->call_modify_callbacks();
357 }
358 }
359 //-----------------------------------------------------------------------------
save_file(const char * newfile,ScriptWindow * e)360 void save_file(const char *newfile, ScriptWindow *e)
361 {
362 if (textbuf->savefile(newfile))
363 fl_alert(_("Error writing to file \'%s\':\n%s."), newfile, strerror(errno));
364 else
365 {
366 filename = newfile; add_filename(filename.c_str(),e);
367 changed = 0; textbuf->call_modify_callbacks();
368 }
369 }
370 //-----------------------------------------------------------------------------
undo_cb(Fl_Widget *,void * v)371 void undo_cb(Fl_Widget*, void* v)
372 {
373 ScriptWindow* e = (ScriptWindow*)v;
374 Fl_Text_Editor::kf_undo(0, e->editor);
375 }
376 //-----------------------------------------------------------------------------
select_all_cb(Fl_Widget *,void * v)377 void select_all_cb(Fl_Widget *, void *v)
378 {
379 ScriptWindow* e = (ScriptWindow*)v;
380 Fl_Text_Editor::kf_select_all(0, e->editor);
381 }
382 //-----------------------------------------------------------------------------
copy_cb(Fl_Widget *,void * v)383 void copy_cb(Fl_Widget*, void* v)
384 {
385 ScriptWindow* e = (ScriptWindow*)v;
386 Fl_Text_Editor::kf_copy(0, e->editor);
387 }
388 //-----------------------------------------------------------------------------
cut_cb(Fl_Widget *,void * v)389 void cut_cb(Fl_Widget*, void* v)
390 {
391 ScriptWindow* e = (ScriptWindow*)v;
392 Fl_Text_Editor::kf_cut(0, e->editor);
393 }
394 //-----------------------------------------------------------------------------
hide_cb(Fl_Widget *,void * v)395 void hide_cb(Fl_Widget*, void* v)
396 {
397 ScriptWindow* e = (ScriptWindow*)v;
398 int p1,p2;
399 textbuf->selection_position(&p1, &p2);
400 if(!textbuf->selected()) p2=p1=e->editor->insert_position();
401 p1 = textbuf->line_start(p1);
402 while(p1<p2)
403 {
404 textbuf->insert(p1,"#h ");
405 int p = textbuf->line_start(textbuf->line_end(p1)+1);
406 if(p!=p1) p1=p; else return;
407 }
408 }
409 //-----------------------------------------------------------------------------
unhide_cb(Fl_Widget *,void * v)410 void unhide_cb(Fl_Widget*, void* v)
411 {
412 ScriptWindow* e = (ScriptWindow*)v;
413 int p1,p2;
414 textbuf->selection_position(&p1, &p2);
415 if(!textbuf->selected()) p2=p1=e->editor->insert_position();
416 p1 = textbuf->line_start(p1);
417 while(p1<p2)
418 {
419 if(textbuf->char_at(p1)=='#')
420 {
421 if(textbuf->char_at(p1+1)=='h' && textbuf->char_at(p1+2)==' ')
422 textbuf->remove(p1,p1+3);
423 else textbuf->remove(p1,p1+1);
424 }
425 int p = textbuf->line_start(textbuf->line_end(p1)+1);
426 if(p!=p1) p1=p; else return;
427 }
428 }
429 //-----------------------------------------------------------------------------
delete_cb(Fl_Widget *,void *)430 void delete_cb(Fl_Widget*, void*) { textbuf->remove_selection(); }
431 //-----------------------------------------------------------------------------
cb_descr(Fl_Widget *,void * v)432 void cb_descr(Fl_Widget*,void *v)
433 {
434 static size_t len=0;
435 ScriptWindow *w = (ScriptWindow*)v;
436 if(!textbuf || !Parse || !w) return;
437 int cur = w->editor->insert_position(), br=0;
438 int beg = textbuf->line_start(cur);
439 const char *s = textbuf->text();
440 for(int i=beg;i<cur;i++)
441 {
442 if(strchr("({[",s[i])) br++;
443 if(strchr(")}]",s[i])) br--;
444 if(br==0 && s[i]==':' && i+1<cur) beg=i+1;
445 }
446 for(br=beg;s[br]>' ' && s[br]!=':';br++);
447 std::string cmd(s+beg,br-beg);
448 const char *desc = Parse->CmdDesc(cmd.c_str());
449 const char *form = Parse->CmdFormat(cmd.c_str());
450 static std::string txt;
451 txt = desc?std::string(desc)+": "+form : "";
452 w->set_status(txt.c_str());
453
454 size_t ll = strlen(s);
455 if(complete_word && br==cur+1 && br-beg>2 && len<ll) // try complete word
456 {
457 long n = Parse->GetCmdNum();
458 std::vector<std::string> vars;
459 for(long i=0;i<n;i++)
460 {
461 const char *c = Parse->GetCmdName(i);
462 if(!strncmp(c,cmd.c_str(),cmd.length())) vars.push_back(c);
463 }
464 for(size_t i=0;i<vars.size();i++)
465 if(vars[i].length()>cmd.length())
466 {
467 std::string suggest = vars[i].substr(cmd.length());
468 textbuf->insert(cur+1, suggest.c_str());
469 textbuf->select(cur+1, cur+suggest.length()+1);
470 break;
471 }
472 }
473 len = ll;
474 }
475 //-----------------------------------------------------------------------------
set_status(const char * txt)476 void ScriptWindow::set_status(const char *txt)
477 { if(txt && status) { status->label(txt); redraw(); } }
478 //-----------------------------------------------------------------------------
changed_cb(int pos,int nInserted,int nDeleted,int nRestyled,const char * deletedText,void * v)479 void changed_cb(int pos, int nInserted, int nDeleted, int nRestyled, const char *deletedText, void* v)
480 {
481 if ((nInserted || nDeleted) && !loading) changed = 1;
482 ScriptWindow *w = (ScriptWindow *)v;
483 cb_descr(0,v);
484 set_title(w);
485 style_update(pos, nInserted, nDeleted, nRestyled, deletedText, w->editor);
486 if (loading) w->editor->show_insert_position();
487 }
488 //-----------------------------------------------------------------------------
489 // void insert_cb(Fl_Widget*, void *v)
490 // {
491 // const char *newfile = mgl_file_chooser(_("Insert file content?"));
492 // ScriptWindow *w = (ScriptWindow *)v;
493 // if (newfile != NULL) load_file(newfile, w->editor->insert_position(),w);
494 // }
495 //-----------------------------------------------------------------------------
paste_cb(Fl_Widget *,void * v)496 void paste_cb(Fl_Widget*, void* v)
497 {
498 ScriptWindow* e = (ScriptWindow*)v;
499 Fl_Text_Editor::kf_paste(0, e->editor);
500 }
501 //-----------------------------------------------------------------------------
502 #include "../widgets/image.h"
503 #include "xpm/box.xpm"
add_editor(ScriptWindow * w,int txtW,int wndH)504 Fl_Widget *add_editor(ScriptWindow *w, int txtW, int wndH)
505 {
506 Fl_Window *w1=new Fl_Window(0,30,txtW,wndH-55,0);
507 Fl_Group *g = new Fl_Group(0,0,txtW-10,30);
508 Fl_Button *o;
509
510 o = new Fl_Button(0, 1, 25, 25); o->image(img_load); o->callback(open_cb,w);
511 o->tooltip(_("Open script or data file"));
512 o = new Fl_Button(25, 1, 25, 25); o->image(img_save); o->callback(save_cb,w);
513 o->tooltip(_("Save script to file"));
514
515 o = new Fl_Button(55, 1, 25, 25); o->image(img_copy); o->callback(copy_cb,w);
516 o->tooltip(_("Copy selection to clipboard"));
517 o = new Fl_Button(80, 1, 25, 25); o->image(img_paste);o->callback(paste_cb,w);
518 o->tooltip(_("Paste text from clipboard"));
519 o = new Fl_Button(105, 1, 25, 25); o->image(img_find); o->callback(find_dlg_cb,w);
520 o->tooltip(_("Find or replace text"));
521
522 o = new Fl_Button(135, 1, 25, 25); o->image(img_insert); o->callback(newcmd_dlg_cb,w);
523 o->tooltip(_("Insert MGL command"));
524 o = new Fl_Button(160, 1, 25, 25); o->image(img_fname); o->callback(ins_fname_cb,w);
525 o->tooltip(_("Insert filename"));
526 o = new Fl_Button(185, 1, 25, 25); o->image(new Fl_Pixmap(box_xpm)); o->callback(inplot_dlg_cb,w);
527 o->tooltip(_("Insert inplot command"));
528
529 o = new Fl_Button(210, 1, 25, 25); o->image(img_calc); o->callback(calc_dlg_cb,w);
530 o->tooltip(_("Show calculator window"));
531 o = new Fl_Button(240, 1, 25, 25); o->image(img_curve);o->callback(prim_dlg_cb,w);
532 o->tooltip(_("Show window for primitives"));
533 g->end(); g->resizable(0);
534
535 w->editor = new Fl_Text_Editor(0, 28, txtW, wndH-85);
536 w->editor->textfont(FL_COURIER);
537 w->editor->buffer(textbuf);
538 w->editor->highlight_data(stylebuf, styletable, sizeof(styletable) / sizeof(styletable[0]), 'A', style_unfinished_cb, 0);
539 #if MGL_HAVE_FL_COPY
540 w->editor->linenumber_width(30);
541 #endif
542 // w->editor->when(FL_WHEN_RELEASE_ALWAYS); w->editor->callback(cb_descr,w);
543
544 textbuf->add_modify_callback(changed_cb, w);
545 textbuf->call_modify_callbacks();
546
547 w1->end(); w1->resizable(w->editor);
548 return w1;
549 }
550 //-----------------------------------------------------------------------------
551 void cp_find_next(Fl_Widget*,void*);
552 void cp_repl_next(Fl_Widget*,void*);
553 void cp_repl_all(Fl_Widget*,void*);
554 class FindDlg : public GeneralDlg
555 {
556 Fl_Input *find, *replace;
557 Fl_Check_Button *mcase, *sback;
558 public:
FindDlg()559 FindDlg() : GeneralDlg()
560 {
561 Fl_Button* o;
562 w = new Fl_Double_Window(375, 130, _("Find/Replace"));
563 find = new Fl_Input(90, 10, 180, 25, _("Find what:"));
564 o = new Fl_Return_Button(275, 10, 95, 25, _("Find")); o->callback(cp_find_next);
565 replace = new Fl_Input(90, 40, 180, 25, _("Replace by:"));
566 o = new Fl_Button(275, 40, 95, 25, _("Replace")); o->callback(cp_repl_next);
567 mcase = new Fl_Check_Button(5, 70, 265, 25, _("Match case"));
568 sback = new Fl_Check_Button(5, 95, 265, 25, _("Search backward"));
569 o = new Fl_Button(275, 70, 95, 25, _("Replace all")); o->callback(cp_repl_all);
570 o = new Fl_Button(275, 100, 95, 25, _("Close")); o->callback(cb_dlg_cancel,this);
571 w->end();
572 }
to_find()573 const char *to_find() { return find->value(); }
find_next()574 void find_next()
575 {
576 const char *s = find->value();
577 int c = mcase->value(), b = sback->value();
578 if(s && *s)
579 {
580 int pos = e->editor->insert_position();
581 int found = b ? textbuf->search_backward(pos,s,&pos,c) : textbuf->search_forward(pos,s,&pos,c);
582 if(found)
583 { // Found a match; select and update the position...
584 size_t len = strlen(s);
585 textbuf->select(pos, pos+len);
586 e->editor->insert_position(pos+len);
587 e->editor->show_insert_position();
588 }
589 else fl_alert(_("No occurrences of \'%s\' found!"), s);
590 }
591 }
repl_next()592 void repl_next()
593 {
594 const char *s = find->value();
595 const char *r = replace->value();
596 int c = mcase->value(), b = sback->value();
597 if(s && *s)
598 {
599 int pos = e->editor->insert_position();
600 int found = b ? textbuf->search_backward(pos,s,&pos,c) : textbuf->search_forward(pos,s,&pos,c);
601 if(found)
602 { // Found a match; select and update the position...
603 size_t len = strlen(r);
604 textbuf->select(pos, pos+strlen(s));
605 textbuf->remove_selection();
606 textbuf->insert(pos, r);
607 textbuf->select(pos, pos+len);
608 e->editor->insert_position(pos+len);
609 e->editor->show_insert_position();
610 }
611 else fl_alert(_("No occurrences of \'%s\' found!"), s);
612 }
613 }
repl_all()614 void repl_all()
615 {
616 const char *s = find->value();
617 const char *r = replace->value();
618 int c = mcase->value(), b = sback->value();
619 int found = (s && *s)?1:0;
620 long num=0;
621 while(found)
622 {
623 int pos = e->editor->insert_position();
624 int found = b ? textbuf->search_backward(pos,s,&pos,c) : textbuf->search_forward(pos,s,&pos,c);
625 if(!found) break;
626 size_t len = strlen(r);
627 textbuf->select(pos, pos+strlen(s));
628 textbuf->remove_selection();
629 textbuf->insert(pos, r);
630 textbuf->select(pos, pos+len);
631 e->editor->insert_position(pos+len);
632 e->editor->show_insert_position();
633 num++;
634 }
635 if(num) fl_message(_("Replaced %ld occurrences."), num);
636 else fl_alert(_("No occurrences of \'%s\' found!"), s);
637 }
638 } find_dlg;
639 //-----------------------------------------------------------------------------
cp_find_next(Fl_Widget *,void *)640 void cp_find_next(Fl_Widget*,void*) { find_dlg.find_next(); }
cp_repl_next(Fl_Widget *,void *)641 void cp_repl_next(Fl_Widget*,void*) { find_dlg.repl_next(); }
cp_repl_all(Fl_Widget *,void *)642 void cp_repl_all(Fl_Widget*,void*) { find_dlg.repl_all(); }
643 //-----------------------------------------------------------------------------
find_dlg_cb(Fl_Widget *,void * v)644 void find_dlg_cb(Fl_Widget*,void *v)
645 { find_dlg.e = (ScriptWindow*)v; find_dlg.show(); }
646 //-----------------------------------------------------------------------------
find_next_cb(Fl_Widget *,void * v)647 void find_next_cb(Fl_Widget*,void *v)
648 {
649 find_dlg.e = (ScriptWindow*)v;
650 const char *s = find_dlg.to_find();
651 if(s && *s) find_dlg.find_next();
652 else find_dlg.show();
653 }
654 //-----------------------------------------------------------------------------
ins_fname_cb(Fl_Widget *,void * v)655 void ins_fname_cb(Fl_Widget *, void *v)
656 { // TODO: use previous file name?!?
657 ScriptWindow* e = (ScriptWindow*)v;
658 const char *s = mgl_file_chooser(_("Select file name"), "DAT files \t*.{dat,csv}\nHDF files \t*.{hdf,h5}\nImage files \t*.{png,jpg,jpeg}");
659 if(s)
660 {
661 std::string ss=s; ss = '\''+ss+'\'';
662 if(e) e->editor->insert(ss.c_str());
663 else cb_args_set(ss.c_str());
664 }
665 }
666 //-----------------------------------------------------------------------------
ins_path_cb(Fl_Widget *,void * v)667 void ins_path_cb(Fl_Widget *, void *v)
668 {
669 static std::string prev;
670 ScriptWindow* e = (ScriptWindow*)v;
671 const char *s = mgl_dir_chooser(_("Select folder name"), prev.c_str());
672 if(s)
673 {
674 std::string ss=prev=s; ss = '\''+ss+'\'';
675 if(e) e->editor->insert(ss.c_str());
676 else cb_args_set(ss.c_str());
677 }
678 }
679 //-----------------------------------------------------------------------------
ins_fits_cb(Fl_Widget *,void * v)680 void ins_fits_cb(Fl_Widget *, void *v)
681 {
682 ScriptWindow* e = (ScriptWindow*)v;
683 HMGL gr = e->graph->get_graph();
684 std::string ss=mgl_get_fit(gr);
685 if(ss.empty()) fl_alert(_("There is no fitted formula."));
686 else { ss = '\''+ss+'\''; e->editor->insert(ss.c_str()); }
687 }
688 //-----------------------------------------------------------------------------
ins_prim_cb(Fl_Widget *,void * v)689 void ins_prim_cb(Fl_Widget *, void *v)
690 {
691 ScriptWindow* e = (ScriptWindow*)v;
692 std::string ss = "subplot 1 1 0 '#'\n"+e->graph->FMGL->prim+"subplot 1 1 0\n###### end of primitives\n";
693 e->editor->insert(ss.c_str());
694 e->graph->FMGL->prim.clear();
695 }
696 //-----------------------------------------------------------------------------
697