1 // -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -g -c Input.cc -Wall" -*- 2 /* 3 * Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #ifdef HAVE_CONFIG_H 20 #include "config.h" 21 #endif 22 #ifndef IN_GIAC 23 #include <giac/first.h> 24 #else 25 #include "first.h" 26 #endif 27 #include <string> 28 #ifdef HAVE_LIBFLTK 29 #include "Input.h" 30 #include <FL/Fl.H> 31 #include <FL/fl_draw.H> 32 #include <FL/Fl_Window.H> 33 #include <FL/fl_ask.H> 34 #include <FL/Fl_File_Chooser.H> 35 #include <FL/Fl_Hold_Browser.H> 36 #include <FL/Fl_Return_Button.H> 37 #include <FL/Fl_Tooltip.H> 38 #include "History.h" 39 #include "Xcas1.h" 40 #include "Tableur.h" 41 #include "Graph3d.h" 42 #include "Help1.h" 43 #ifndef IN_GIAC 44 #include <giac/plot.h> 45 #include <giac/help.h> 46 #include <giac/global.h> 47 #else 48 #include "plot.h" 49 #include "help.h" 50 #include "global.h" 51 #endif 52 #include <iostream> 53 #include <fstream> 54 #ifdef HAVE_UNISTD_H 55 #include <unistd.h> 56 #endif 57 using namespace std; 58 59 #ifndef NO_NAMESPACE_XCAS 60 namespace xcas { 61 #endif // ndef NO_NAMESPACE_XCAS 62 63 #define TAB_ARGS 6 64 65 #if defined __APPLE__ || defined WIN32 66 bool use_external_browser = true ; 67 #else 68 bool use_external_browser = getenv("BROWSER") ; 69 #endif 70 std::vector<std::string> Multiline_Input_tab::history; 71 int Multiline_Input_tab::count=0; 72 73 Fl_Help_Dialog * Xcas_help_window = new Fl_Help_Dialog(); 74 Fl_Widget * Xcas_input_focus=0; 75 system_browser(const string & s)76 void system_browser(const string & s){ 77 int i=giac::system_no_deprecation(s.c_str()); 78 if (i!=0){ 79 fl_alert("%s",("Switching to internal browser, error running browser command "+s).c_str()); 80 use_external_browser=false; 81 } 82 } 83 read_aide(const string & progname,int language)84 bool read_aide(const string & progname,int language){ 85 string helpfile("aide_cas"); 86 int helpitems=0; 87 (*giac::vector_aide_ptr())=giac::readhelp(helpfile.c_str(),helpitems,false); 88 if (!helpitems){ 89 if (getenv("XCAS_HELP")) 90 helpfile=getenv("XCAS_HELP"); 91 else 92 helpfile=giac::giac_aide_dir()+"aide_cas"; 93 (*giac::vector_aide_ptr())=giac::readhelp(helpfile.c_str(),helpitems); 94 } 95 if (!helpitems){ 96 cerr << "// Unable to open help file "<< helpfile << '\n'; 97 return false; 98 } 99 else { 100 cerr << "// Using help file " << helpfile << '\n'; 101 giac::xcasroot()=giac::xcasroot_dir((char *) progname.c_str()); 102 /* patch for gsview TEMP, but does not work 103 if (!getenv("TEMP")){ 104 if (giac::is_file_available("/tmp")) 105 setenv("TEMP","/tmp",1); 106 else 107 setenv("TEMP",giac::xcasroot().c_str(),1); 108 } 109 */ 110 cerr << "// root dir " << giac::xcasroot() << '\n'; 111 giac::html_help_init((char *) progname.c_str(),language); 112 giac::update_completions(); 113 return true; 114 } 115 } 116 117 // return the last keyword of s motclef(const std::string & s)118 std::string motclef(const std::string & s){ 119 int l=s.size(); 120 int i=l-1; 121 for (;i>=0;i--){ 122 if (giac::isalphan(s[i])) 123 break; 124 } 125 l=i+1; 126 for (;i>=0;i--){ 127 if (!giac::isalphan(s[i])) 128 return s.substr(i+1,l-1-i); 129 } 130 return s.substr(0,l); 131 } 132 findtooltip(const giac::gen & g)133 string findtooltip(const giac::gen & g){ 134 string s,s1,s2; 135 static const char * tooltip_tab[]={"Integer","Expression","Variable","Matrix","Function","String","Polynom","Vector","Point","List","List of point","List of reals","List of integers","Sequence of variables","Command",}; 136 static const char * tooltip_name[]={"Intg","Expr","Var","Mtrx","Fnc","Str","Poly","Vect","Pnt","Lst","LstPnt","LstReal","LstIntg","SeqVar","Cmd",0}; 137 if (g.is_symb_of_sommet(giac::at_ou)){ 138 giac::gen & f = g._SYMBptr->feuille; 139 if (f.type==giac::_VECT){ 140 giac::const_iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end(); 141 if (it!=itend){ 142 for (s=findtooltip(*it),++it;it!=itend;++it) 143 s = s + gettext(" or ") + findtooltip(*it); 144 } 145 } 146 return s; 147 } 148 if (g.type==giac::_VECT && g._VECTptr->size()==1) 149 return findtooltip(g._VECTptr->front())+"(optional)"; 150 s = g.print(giac::context0); 151 int l=s.size(); 152 int p=s.find('('); 153 if (p>0 && p<l){ 154 s1 = s.substr(0,p); s2=s.substr(p,l); 155 } 156 else s1=s; 157 const char ** tooltip_ptr=tooltip_name; 158 for (;*tooltip_ptr;++tooltip_ptr){ 159 if (*tooltip_ptr==s1){ 160 return tooltip_tab[tooltip_ptr-tooltip_name]+s2; 161 } 162 } 163 return s; 164 } 165 split(const std::string & s,Fl_Widget * w)166 std::string split(const std::string & s,Fl_Widget * w){ 167 fl_font(w->labelfont(),w->labelsize()); 168 string res,ajout; 169 int fin=s.size(),debut=0; 170 int taille=w->w(); 171 for (;debut<fin;){ 172 int l=fin-debut; 173 ajout=s.substr(debut,l); 174 if (fl_width(ajout.c_str())<=taille) 175 return res+ajout; 176 for (--l;l>0;--l){ 177 if (s[debut+l]==' '){ 178 ajout=s.substr(debut,l); 179 if (fl_width(ajout.c_str())<=taille){ 180 res += ajout; 181 res += '\n'; 182 break; 183 } 184 } 185 } 186 if (l==0) 187 return res+ajout; 188 debut += l+1; 189 } 190 return res; 191 } 192 update_examples(const string & s,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language)193 void update_examples(const string & s,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language){ 194 help_output(s,language); 195 if (output->label()) 196 delete output->label(); 197 char * ptr=new char [s.size()+1]; 198 strcpy(ptr,s.c_str()); 199 output->label(ptr); 200 if (output->parent()) 201 output->parent()->redraw(); 202 if (examples && output ){ 203 giac::aide cur_aide=giac::helpon(s,(*giac::vector_aide_ptr()),language,(*giac::vector_aide_ptr()).size(),false); 204 string result=cur_aide.cmd_name; 205 if (!cur_aide.syntax.empty()){ 206 result=result+"("+cur_aide.syntax+")\n"; 207 giac::gen helpg; 208 giac::vecteur helpv; 209 if (!cur_aide.syntax.empty()){ 210 helpg=giac::gen(cur_aide.syntax,giac::context0); 211 if (helpg.type==giac::_VECT) 212 helpv=*helpg._VECTptr; 213 else 214 helpv=giac::vecteur(1,helpg); 215 } 216 giac::const_iterateur jt=helpv.begin(),jtend=helpv.end(); 217 Fl_Input ** ptr=argtab, ** argtabend=argtab+TAB_ARGS; 218 if (jtend-jt>TAB_ARGS) 219 jtend=jt+TAB_ARGS; 220 for (;*ptr && jt!=jtend;++jt,++ptr){ 221 giac::gen tmp=*jt; 222 string tmps=tmp.print(giac::context0); 223 if (tmp.type==giac::_VECT) 224 (*ptr)->labelcolor(FL_BLUE); 225 else 226 (*ptr)->labelcolor(FL_BLACK); 227 if ((*ptr)->label()) 228 free((void *) (*ptr)->label()); 229 char * chartab = (char *) malloc(sizeof(char)*(tmps.size()+1)); 230 strcpy(chartab,tmps.c_str()); 231 (*ptr)->label(chartab); 232 (*ptr)->show(); 233 (*ptr)->value(""); 234 tmps = findtooltip(tmp); 235 if ((*ptr)->tooltip()) 236 free((void *) (*ptr)->tooltip()); 237 char * chartab2 = (char *) malloc(sizeof(char)*(tmps.size()+1)); 238 strcpy(chartab2,tmps.c_str()); 239 (*ptr)->tooltip(chartab2); 240 } 241 int L=output->labelsize()+2; 242 int eh=L*((1+(ptr-argtab))/2); 243 int outputyh = output->y()+output->h(); 244 examples->resize(examples->x(),outputyh+eh,examples->w(),examples->parent()->h()-outputyh-eh-2); 245 for (;ptr!=argtabend;++ptr){ 246 if (*ptr) 247 (*ptr)->hide(); 248 } 249 } 250 vector<giac::localized_string>::const_iterator it=cur_aide.blabla.begin(),itend=cur_aide.blabla.end(); 251 for (;it!=itend;++it){ 252 if (it->language==language){ 253 result = split(it->chaine,output) +'\n'+result ; 254 break; 255 } 256 } 257 output->value(result.c_str()); 258 examples->clear(); 259 examples->add(s.c_str()); 260 std::vector<std::string>::const_iterator jt=cur_aide.examples.begin(),jtend=cur_aide.examples.end(); 261 for (;jt!=jtend;++jt) 262 examples->add(jt->c_str()); 263 related->clear(); 264 syns->clear(); 265 std::vector<giac::indexed_string>::const_iterator kt=cur_aide.related.begin(),ktend=cur_aide.related.end(); 266 for (;kt!=ktend;++kt){ 267 string tmp=giac::localize(kt->chaine,language); 268 related->add(tmp.c_str()); 269 } 270 std::vector<giac::localized_string>::const_iterator lt=cur_aide.synonymes.begin(),ltend=cur_aide.synonymes.end(); 271 for (;lt!=ltend;++lt){ 272 if (lt->chaine!=s) 273 syns->add(lt->chaine.c_str()); 274 } 275 } 276 } 277 handle_tab_cb_browser(Fl_Browser * b,void *)278 void handle_tab_cb_browser(Fl_Browser * b,void *){ 279 int k=b->value(); 280 if (k>=1){ 281 string s=b->text(k); 282 // find examples browser 283 Fl_Group * g = b->parent(); 284 Fl_Browser * examples=0, * related=0,*syns=0; 285 Fl_Output * output=0; 286 Fl_Input * input=0,*argtab[TAB_ARGS]={0,0,0,0,0,0}; 287 if (g){ 288 int n=g->children(); 289 for (int i=0;i<n-1;i++){ 290 if (i>4 && (output=dynamic_cast<Fl_Output *>(g->child(i)))){ 291 related=dynamic_cast<Fl_Browser *>(g->child(i-4)); 292 syns=dynamic_cast<Fl_Browser *>(g->child(i-3)); 293 examples=dynamic_cast<Fl_Browser *>(g->child(i+7)); 294 input=dynamic_cast<Fl_Input *>(g->child(i-1)); 295 for (int k=0;k<TAB_ARGS;k++){ 296 argtab[k] = dynamic_cast<Fl_Input *>(g->child(i+1+k)); 297 } 298 break; 299 } 300 } 301 } 302 if (output && input && examples && related && syns){ 303 update_examples(s,examples,related,syns,output,argtab,giac::language(giac::context0)); 304 input->value(b->text(k)); 305 if (Fl::event_clicks()){ 306 g->hide(); 307 } 308 } 309 else 310 help_output(s,giac::language(giac::context0)); 311 } 312 } 313 browser_html_help(Fl_Browser * b,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language)314 void browser_html_help(Fl_Browser * b,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language){ 315 int k=b->value(); 316 if (k>=1){ 317 if (Xcas_help_window){ 318 string s=b->text(k); 319 update_examples(s,examples,related,syns,output,argtab,language); 320 std::map<std::string,std::string>::const_iterator it=giac::lexer_localization_map().find(s),itend=giac::lexer_localization_map().end(); 321 if (it!=itend) 322 s=it->second; 323 vector<string> v=giac::html_help(giac::html_mtt,s); 324 if (!v.empty()){ 325 if (use_external_browser) 326 giac::system_browser_command(v.front()); 327 else { 328 Xcas_help_window->load(v.front().c_str()); 329 if (!xcas::Xcas_help_window->visible()) 330 xcas::Xcas_help_window->show(); 331 } 332 } 333 } 334 b->window()->show(); 335 Fl::focus(b); 336 } 337 } 338 339 Fl_Window * handle_tab_w = 0; 340 // Find a completion of s in v -> ans, return true if user OK 341 // dx,dy=size of browser window handle_tab(const string & s,const vector<string> & v,int dx,int dy,int & remove,string & ans,bool allow_immediate_out)342 int handle_tab(const string & s,const vector<string> & v,int dx,int dy,int & remove,string & ans,bool allow_immediate_out){ 343 static Fl_Hold_Browser * browser = 0; 344 static Fl_Hold_Browser * related = 0; 345 static Fl_Hold_Browser * syns = 0; 346 static Fl_Button * button0 = 0 ; 347 static Fl_Button * button1 =0; 348 static Fl_Button * button2 =0; 349 static Fl_Button * topic_help=0; 350 static Fl_Input * input = 0; 351 static Fl_Multiline_Output * output = 0; 352 static Fl_Hold_Browser * examples = 0; 353 static Fl_Input * argtab[TAB_ARGS]={0,0,0,0,0,0}; 354 int L=16; 355 const giac::context * contextptr=giac::context0; 356 if (xcas::Xcas_input_focus && xcas::Xcas_input_focus->window()){ 357 dx=4*xcas::Xcas_input_focus->window()->w()/5; 358 dy=4*xcas::Xcas_input_focus->window()->h()/5; 359 L=xcas::Xcas_input_focus->labelsize()+2; 360 contextptr=get_context(xcas::Xcas_input_focus); 361 } 362 else { 363 if (dx>500) 364 dx=500; 365 } 366 if (dy<300) 367 dy=300; 368 if (dx<240) 369 dx=240; 370 // search non ascii char in s starting from the end 371 int ss=s.size(); 372 string res; 373 remove=0; 374 for (int i=ss-1;i>=0;--i,++remove){ 375 const char & ch =s[i]; 376 if (giac::isalphan(ch) || ch=='&' || ch=='|' || ch=='=' || ch==':' || ch=='@' || ch=='<' || ch=='>' || ch=='+' || ch=='-' || ch=='/' || ch=='*' || ch=='$' || ch=='%') 377 res=ch+res; 378 else { 379 if (!res.empty()) 380 break; 381 } 382 } 383 ss=res.size(); 384 if (!handle_tab_w){ 385 Fl_Group::current(0); 386 handle_tab_w=new Fl_Window(50,100,dx,dy,gettext("Index")); 387 button0 = new Fl_Button(2,2,dx/3-4,L+2); 388 button0->shortcut(0xff0d); 389 button0->label(gettext("OK")); 390 button0->tooltip(gettext("Click to copy the commandname to the commandline")); 391 button1 = new Fl_Button(dx/3+2,2,dx/3-4,L+2); 392 button1->shortcut(0xff1b); 393 button1->label(gettext("Cancel")); 394 button2 = new Fl_Button(2*dx/3+2,2,dx/3-4,L+2); 395 button2->label(gettext("Details")); 396 button2->tooltip(gettext("Show full HTML help in browser")); 397 browser = new Fl_Hold_Browser(2,2*L+4,dx/2-2,dy/2-(2*L+4)); 398 browser->format_char(0); 399 browser->type(2); 400 browser->label(gettext("Index")); 401 browser->align(FL_ALIGN_TOP); 402 browser->callback((Fl_Callback*)handle_tab_cb_browser); 403 // order is important: related,syns, examples,input,output 404 related = new Fl_Hold_Browser(dx/2+2,2*L+4,dx/2-2,dy/4-(L+2)); 405 related->label(gettext("Related")); 406 related->format_char(0); 407 related->align(FL_ALIGN_TOP); 408 related->tooltip(gettext("Click for help on related command")); 409 syns = new Fl_Hold_Browser(dx/2+2,related->y()+related->h()+L+2,dx/2-2,dy/4-(2*L+4)); 410 syns->format_char(0); 411 syns->label(gettext("Synonyms")); 412 syns->align(FL_ALIGN_TOP); 413 topic_help = new Fl_Button(0,browser->y()+browser->h(),L,L+4); 414 topic_help->label("?"); 415 topic_help->tooltip(gettext("Search this word in HTML help")); 416 input = new Fl_Input(L,browser->y()+browser->h(),dx-L,L+4); 417 input->when(FL_WHEN_CHANGED |FL_WHEN_ENTER_KEY |FL_WHEN_NOT_CHANGED); 418 // input->label("?"); 419 input->tooltip(gettext("Show commandnames starting from this text")); 420 output = new Fl_Multiline_Output(2,input->y()+input->h(),dx-4,3*L+9); 421 output->tooltip(gettext("Command short description and syntax")); 422 // arguments 423 int ypos=output->y()+output->h(); 424 for (int j=0;j<TAB_ARGS;j++){ 425 argtab[j]= new Fl_Input(dx/4+(j%2)*dx/2,ypos+1+(j/2)*L,dx/4,L-1); 426 argtab[j]->when(FL_WHEN_ENTER_KEY |FL_WHEN_NOT_CHANGED); 427 } 428 ypos += 3*L; 429 examples = new Fl_Hold_Browser(output->x(),ypos,output->w(),handle_tab_w->h()-output->y()-output->h()-2-3*L); 430 examples->label("Examples"); 431 examples->type(2); 432 examples->align(FL_ALIGN_LEFT); 433 examples->tooltip(gettext("Left-click: copy example to commandline, right-click: fill in template with example values")); 434 handle_tab_w->end(); 435 handle_tab_w->resizable(handle_tab_w); 436 change_group_fontsize(handle_tab_w,L-2); 437 } 438 else { 439 browser->clear(); 440 examples->clear(); 441 related->clear(); 442 } 443 if (ss) 444 input->value(res.c_str()); 445 else { 446 res=input->value(); 447 ss=res.size(); 448 allow_immediate_out=false; 449 } 450 input->position(ss,ss); 451 vector<string> vres; 452 int vs=v.size(),i=0,r=-1,i_=0; 453 for (int k=0;k<vs;++k){ 454 vres.push_back(v[k]); 455 browser->add(v[k].c_str()); 456 if (!i && v[k].substr(0,ss)==res){ 457 i=k+1; 458 } 459 if (v[k][0]==res[0]){ 460 i_=k+1; 461 } 462 } 463 if (!i){ 464 if (allow_immediate_out) 465 return 0; 466 else 467 i=i_; 468 if (!i) 469 i=1; 470 } 471 handle_tab_w->set_modal(); 472 if (vs){ 473 browser->value(i); 474 string bt=browser->text(i); 475 update_examples(bt,examples,related,syns,output,argtab,giac::language(contextptr)); 476 handle_tab_w->show(); 477 handle_tab_w->hotspot(handle_tab_w); 478 Fl::focus(input); 479 for (;;) { 480 if (!handle_tab_w->shown()){ 481 r=0; break; 482 } 483 Fl_Widget *o = Fl::readqueue(); 484 if (!o) Fl::wait(); 485 else { 486 if (o == topic_help){ help_fltk(input->value()); } 487 if (o == button0) {r = 0; break;} 488 if (o == button1) {r = 1; break;} 489 if (o == button2) browser_html_help(browser,examples,related,syns,output,argtab,giac::language(contextptr)); 490 int j=0; 491 for (;j<TAB_ARGS;j++){ 492 if (o==argtab[j]){ 493 cerr << j << '\n'; 494 Fl::e_keysym=argtab[j]->value()[0]; 495 break; 496 } 497 } 498 if (j!=TAB_ARGS){ r=0; break; } 499 if ( o == examples && examples->value() ) { 500 string tmp=examples->text(examples->value()); 501 if (Fl::event_button()!=3 || (!tmp.empty() && tmp[0]==' ')){ 502 r=2; 503 break; 504 } 505 giac::gen tmpg(tmp,contextptr); 506 if (browser->value()>=1 && tmpg.type==giac::_SYMB && tmpg._SYMBptr->sommet==giac::gen(browser->text(browser->value()),contextptr)) 507 tmpg=tmpg._SYMBptr->feuille; 508 giac::vecteur v; 509 if (tmpg.type==giac::_VECT && tmpg.subtype==giac::_SEQ__VECT) 510 v=*tmpg._VECTptr; 511 else 512 v=giac::vecteur(1,tmpg); 513 int vs=v.size(); 514 for (int j=0;j<TAB_ARGS && j<vs;++j){ 515 if (argtab && argtab[j]) 516 argtab[j]->value(v[j].print(contextptr).c_str()); 517 } 518 } 519 if ( o == related && related->value() ) { 520 string s=related->text(related->value()); 521 update_examples(s,examples,related,syns,output,argtab,giac::language(contextptr)); 522 for (i=0;i<vs;++i){ 523 if (v[i]==s){ 524 browser->value(i+1); 525 break; 526 } 527 } 528 } 529 if ( o == syns && syns->value() ) { 530 string s=syns->text(syns->value()); 531 update_examples(s,examples,related,syns,output,argtab,giac::language(contextptr)); 532 for (i=0;i<vs;++i){ 533 if (v[i]==s){ 534 browser->value(i+1); 535 break; 536 } 537 } 538 } 539 if (o == handle_tab_w) { r=1; break; } 540 if (o == input){ 541 if (Fl::event_key(FL_Enter) || Fl::event_key(FL_KP_Enter)){ 542 if (Fl::event_state(FL_SHIFT |FL_CTRL | FL_ALT)){ 543 Fl::focus(examples); 544 browser_html_help(browser,examples,related,syns,output,argtab,giac::language(contextptr)); 545 } 546 else { 547 r=0; 548 break; 549 } 550 } 551 else { 552 const char * entree=input->value(); 553 char nentree[256]; nentree[255]=0; 554 char nch[256]; nentree[255]=0; 555 for (int j=0;j<255;++j){ 556 nentree[j]=tolower(entree[j]); 557 if (!entree[j]) break; 558 } 559 for (i=1;i<=vs;++i){ 560 const char * ch=browser->text(i); 561 for (int j=0;j<255;++j){ 562 nch[j]=tolower(ch[j]); 563 if (!ch[j]) break; 564 } 565 if (ch){ 566 int comp=strcmp(nch,nentree); 567 if (!comp) 568 comp=strcmp(ch,entree); 569 if (comp>=0) 570 break; 571 } 572 } 573 if (i<=vs){ 574 browser->value(i); 575 update_examples(browser->text(i),examples,related,syns,output,argtab,giac::language(contextptr)); 576 } 577 } 578 } 579 } 580 } 581 /* does not work properly, since focus might change 582 if (foc && foc->window()) 583 foc->window()->show(); 584 else 585 */ 586 handle_tab_w->hide(); 587 // Xcas_help_window->hide(); 588 i=browser->value(); 589 } 590 // delete browser; 591 // delete button1; 592 // delete button0; 593 // delete w; 594 int j=examples->value(); // ,k=related->value(); 595 if (r==2 && j<=examples->size() && j>0){ 596 ans=examples->text(j); 597 return 2; 598 } 599 if (r==0 && i<=vs && i>0){ 600 ans=vres[i-1]; 601 string addans; 602 Fl_Input ** ptr=argtab; 603 if (ptr && *ptr && (*ptr)->visible()){ 604 addans = "("; 605 for (int j=0;*ptr && j<TAB_ARGS;++j){ 606 string tmp=(*ptr)->value(); 607 if (tmp.empty()) 608 continue; 609 addans += tmp; 610 ++ptr; 611 if (!(*ptr)->visible()) 612 break; 613 addans += ","; 614 } 615 if (addans[addans.size()-1]==',') 616 addans=addans.substr(0,addans.size()-1); 617 addans += ")"; 618 } 619 if (addans.size()>2){ 620 ans += addans; 621 return 2; 622 } 623 return 1; 624 } 625 else 626 return 0; 627 } 628 629 insert_replace(const string & chaine,bool selected)630 void Multiline_Input_tab::insert_replace(const string & chaine,bool selected){ 631 size_t pos1=position(); 632 size_t pos2=mark(); 633 if (pos1>pos2){ 634 size_t tmp=pos1; 635 pos1=pos2; 636 pos2=tmp; 637 } 638 string input_s(value()),new_input; 639 size_t l=input_s.size(); 640 new_input=input_s.substr(0,pos1)+chaine; 641 if (pos2<l) 642 new_input += input_s.substr(pos2,l-pos2); 643 value(new_input.c_str()); 644 pos2=pos1+string(chaine).size(); 645 if (selected) 646 position(pos1,pos2); 647 else 648 position(pos2,pos2); 649 set_changed(); 650 } 651 Multiline_default_callback(Fl_Widget * w,void *)652 void Multiline_default_callback(Fl_Widget * w,void *){ 653 w->handle(FL_ENTER); 654 } 655 Multiline_Input_tab(int x,int y,int w,int h,const char * l)656 Multiline_Input_tab::Multiline_Input_tab(int x,int y,int w,int h,const char * l): 657 Fl_Multiline_Input(x, y, w, h, l),handling(false),completion_tab(giac::vector_completions_ptr()),tableur(0),_g(giac::undef) { 658 if (parent()){ 659 labelfont(parent()->labelfont()); 660 labelsize(parent()->labelsize()); 661 textfont(parent()->labelfont()); 662 textsize(parent()->labelsize()); 663 } 664 Fl_Widget::callback(Multiline_default_callback); parent_redraw(this); 665 when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED); 666 color(FL_WHITE); 667 textfont(FL_TIMES); 668 } 669 Comment_Multiline_Input(int x,int y,int w,int h,const char * l)670 Comment_Multiline_Input::Comment_Multiline_Input(int x,int y,int w,int h,const char * l): 671 Fl_Multiline_Input(x,y,w,h,l) { 672 if (parent()){ 673 labelfont(parent()->labelfont()); 674 labelsize(parent()->labelsize()); 675 textfont(parent()->labelfont()); 676 textsize(parent()->labelsize()); 677 } 678 parent_redraw(this); 679 color(FL_WHITE); 680 } 681 match()682 void Multiline_Input_tab::match(){ 683 static bool recursive_call=false; 684 if (mark()!=position()) 685 return; 686 int lastkey=Fl::event_key(); 687 if (lastkey!='(' && lastkey!='[' && lastkey!='{' && lastkey!='}' && lastkey!=']' && lastkey!=')' && lastkey!='0' && lastkey!='9' && lastkey!='\'' && lastkey != '=' && lastkey !=FL_Left && lastkey !=FL_Right) 688 return; 689 if (recursive_call) 690 return; 691 recursive_call=true; 692 // check if cursor is on [, (, ), ] 693 int pos=position(),p0=pos; 694 const char * c=value(); 695 int pmax=string(c).size(); 696 bool closing=false,opening=false; 697 if (pos<pmax) 698 opening= c[pos]=='(' || c[pos]=='[' || c[pos]=='{'; 699 if (!opening && pos){ 700 closing = c[pos-1]==')' || c[pos-1]==']' || c[pos-1]=='}'; 701 if (closing) 702 --p0; 703 } 704 if (opening || closing){ 705 Fl::flush(); 706 usleep(100000); 707 if (true || !Fl::get_key(lastkey)){ 708 Fl::check(); 709 int pos=position(),p0=pos; 710 const char * c=value(); 711 int pmax=string(c).size(); 712 bool closing=false,opening=false; 713 if (pos<pmax) 714 opening= c[pos]=='(' || c[pos]=='[' || c[pos]=='{'; 715 if (!opening && pos){ 716 closing = c[pos-1]==')' || c[pos-1]==']' || c[pos-1]=='}'; 717 if (closing) 718 --p0; 719 } 720 if (opening || closing){ 721 bool ok=giac::matchpos(c,p0); 722 if (!ok){ 723 if (closing) 724 p0=pos-1; 725 else 726 p0=pos+1; 727 } 728 else { 729 if (opening && pos<pmax) 730 p0=p0+1; 731 } 732 mark(p0); 733 unsigned s=selection_color(); 734 if (ok){ 735 if (opening) 736 selection_color(FL_GREEN); 737 else 738 selection_color(fl_color_cube(0,FL_NUM_GREEN-1,2)); 739 } 740 else 741 selection_color(FL_RED); 742 damage(damage() | FL_DAMAGE_ALL); 743 redraw(); 744 Fl::flush(); 745 usleep(70000); 746 if (!Fl::ready()){ 747 for (int i=0;i<giac::PARENTHESIS_NWAIT;++i){ 748 usleep(50000); 749 if (Fl::ready()) 750 break; 751 } 752 } 753 selection_color(s); 754 position(pos,pos); 755 damage(damage() | FL_DAMAGE_ALL); 756 redraw(); 757 Fl::flush(); 758 } 759 } 760 } 761 recursive_call=false; 762 } 763 handle(int event)764 int Multiline_Input_tab::handle(int event){ 765 // if (handling) return 0; 766 handling=true; 767 string oldval(value()); 768 int res=in_handle(event); 769 History_Pack * g=get_history_pack(this); 770 if (g && value()!=oldval) 771 g->modified(false); 772 handling=false; 773 return res; 774 } 775 is_text_a_level(const char * ch)776 bool is_text_a_level(const char * ch){ 777 unsigned l=strlen(ch),i; 778 char cmp[]="// fltk "; 779 for (i=0;i<l && i<8;++i){ 780 if (ch[i]!=cmp[i]) 781 return false; 782 } 783 return true; 784 } 785 increase_size(Fl_Widget * wid,int L)786 void increase_size(Fl_Widget * wid, int L){ 787 if (!wid) return; 788 // CERR << "increase size " << L << '\n'; 789 if (L+wid->h()<=wid->labelsize()+4) 790 L=wid->labelsize()+5-wid->h(); 791 if (!L) return; 792 int pos; 793 History_Pack * g = get_history_pack(wid,pos); 794 if (g){ 795 Fl_Group * gr=wid->parent(); 796 // find parents to above history pack 797 std::vector<Fl_Widget *> parents(1,wid); 798 for (;gr && gr!=g;gr=gr->parent()){ 799 parents.push_back(gr); 800 } 801 Fl_Widget * tmp=0,*tmp2; 802 Fl_Group * tmpg=0; 803 int i=parents.size()-1; 804 for (;i>=0;--i){ 805 tmpg=gr; 806 tmp=parents[i]; 807 // move children of gr below tmp 808 int k=tmpg->children(); 809 for (int j=0;j<k;++j){ 810 tmp2=tmpg->child(j); 811 if (tmp2->y()>tmp->y()){ 812 tmp2->resize(tmp2->x(),tmp2->y()+L,tmp2->w(),tmp2->h()); 813 tmp2->redraw(); 814 } 815 else { 816 if (tmp2==tmp){ 817 tmp->Fl_Widget::resize(tmp->x(),tmp->y(),tmp->w(),tmp->h()+L); 818 tmp->redraw(); 819 gr=dynamic_cast<Fl_Group *>(tmp); 820 } 821 } 822 } // end for j 823 } // end for i 824 // recompute pack 825 g->resize(); 826 g->redraw(); 827 } 828 } 829 resize_nl()830 void Multiline_Input_tab::resize_nl(){ 831 if (tableur) 832 return; 833 const char * ch = value(); 834 unsigned i=0,l=strlen(ch),nl=1; 835 for (;i<l;++i){ 836 if (ch[i]=='\n') 837 ++nl; 838 } 839 increase_size(this,6+nl*(labelsize()+2)-h()); 840 } 841 need_nl()842 bool Multiline_Input_tab::need_nl(){ 843 int i=position(),i0; 844 const char * ch=value(); 845 for (i0=i-1;i0>=0;--i0){ 846 if (ch[i0]=='\n') 847 break; 848 } 849 string s=string(ch).substr(i0+1,i-i0-1); 850 fl_font(textfont(),textsize()); 851 int lw=int(1.2*fl_width(s.c_str())); 852 return lw>w()+20; 853 } 854 height(const char * ch,int labelsize)855 int height(const char * ch,int labelsize){ 856 int n=strlen(ch); 857 int h0=labelsize+4,res=n?h0+2:1; 858 int maxh=300; 859 for (int i=0;i<n-1;++i,++ch){ 860 if (*ch=='\n'){ 861 res += h0; 862 if (res>maxh) 863 break; 864 } 865 } 866 return res; 867 } 868 in_handle(int event)869 int Multiline_Input_tab::in_handle(int event){ 870 History_Pack * g=get_history_pack(this); 871 if (g && event==FL_MOUSEWHEEL){ 872 if (!Fl::event_inside(this)) 873 return 0; 874 if (Fl_Scroll * sc = dynamic_cast<Fl_Scroll *>(g->parent())){ 875 int scy=sc->yposition()+labelsize()*Fl::e_dy; 876 if (scy<0) 877 scy=0; 878 #ifdef _HAVE_FL_UTF8_HDR_ 879 sc->scroll_to(sc->xposition(),scy); 880 #else 881 sc->position(sc->xposition(),scy); 882 #endif 883 return 1; 884 } 885 } 886 if (event==FL_FOCUS || event==FL_PUSH || event==FL_KEYBOARD){ 887 Xcas_input_focus=this; 888 autosave_disabled=false; 889 } 890 if (event==FL_FOCUS){ 891 // Fl::focus(this); 892 // redraw(); 893 return Fl_Multiline_Input::handle(event); 894 } 895 if (event==FL_UNFOCUS){ 896 return Fl_Multiline_Input::handle(event); 897 } 898 if (event==FL_PUSH && tableur) 899 tableur->editing=true; 900 if (g && event==FL_PASTE){ 901 // check that it's not a // fltk ... pasting a full level 902 const char * ch=Fl::event_text(); 903 if (ch){ 904 if (is_text_a_level(ch)) 905 return g->handle(event); 906 } 907 if (Fl_Multiline_Input::handle(event)){ 908 if (!tableur){ 909 // add space for ch 910 unsigned i=0,l=strlen(ch),nl=0; 911 for (;i<l;++i){ 912 if (ch[i]=='\n') 913 ++nl; 914 } 915 increase_size(this,nl*(labelsize()+1)); 916 } 917 return 1; 918 } 919 } 920 if (event==FL_KEYBOARD) { 921 static string toolt; 922 string str; 923 int key=Fl::event_key(); 924 if (g && key==FL_F+9){ 925 History_Fold * hf = get_history_fold(g); 926 if (!hf) return 0; 927 hf->eval(); 928 return 1; 929 } 930 if (Fl::event_text()){ 931 int i=Fl::event_text()[0]; 932 switch (i){ 933 case 22: case 25: 934 // Ctrl-V or Ctrl-Y paste, no need to check for level text 935 // because they paste using an FL_PASTE event 936 case 3: case 4: case 5: case 21: case 23: case 24: case 26: 937 if (Fl_Multiline_Input::handle(event)){ 938 resize_nl(); 939 return 1; 940 } 941 break; 942 case 1: 943 position(0); 944 mark(size()); 945 Fl::selection(*this,value(),strlen(value())); 946 return 1; 947 case 2: 948 insert("[]"); 949 position(position()-1,position()-1); 950 return 1; 951 case 11: 952 insert("\n"); 953 resize_nl(); 954 return 1; 955 case 12: 956 insert("{}"); 957 position(position()-1,position()-1); 958 return 1; 959 case ' ': case ',': case '+': 960 if (need_nl()){ 961 Fl_Multiline_Input::handle(event); 962 insert("\n"); 963 resize_nl(); 964 return 1; 965 } 966 break; 967 #ifndef __APPLE__ 968 case '(': 969 // Fl::belowmouse(this); 970 str=motclef(string(value()).substr(0,position())); 971 if (!str.empty()){ 972 toolt=writehelp(helpon(str,*giac::vector_aide_ptr(),giac::language(g?g->contextptr:0),giac::vector_aide_ptr()->size()),giac::language(g?g->contextptr:0)); 973 tooltip(toolt.c_str()); 974 int hh=height(toolt.c_str(),Fl_Tooltip::size()); 975 Fl_Tooltip::enter_area(this,0,-hh,0,0,toolt.c_str()); 976 } 977 break; 978 case ')': 979 tooltip(""); 980 break; 981 #endif 982 } 983 } 984 if (key==FL_Enter || key==FL_KP_Enter){ 985 if (Fl::event_shift() || strlen(value())==0){ 986 insert("\n"); 987 if (!tableur) 988 increase_size(this,labelsize()+1); 989 return 1; 990 } 991 giac::gen val; 992 // keep warnings 993 giac::context * contextptr=g?g->contextptr:0; 994 ostringstream warnings ; 995 #ifdef WITH_MYOSTREAM 996 giac::my_ostream * old=giac::logptr(contextptr); 997 giac::my_ostream newptr(&warnings); 998 logptr(&newptr,contextptr); 999 #else 1000 my_ostream * old=giac::logptr(contextptr); 1001 logptr(&warnings,contextptr); 1002 #endif 1003 giac::first_error_line(contextptr)=0; 1004 try { 1005 val=warn_equal(giac::gen(value(),contextptr),contextptr); 1006 } 1007 catch (...){ 1008 ; 1009 } 1010 string warn0=warnings.str(),curline,debutline; 1011 giac::logptr(old,contextptr); 1012 static string warn; 1013 warn=""; 1014 // Read warn0 lines and skip Parsing and Success in warn 1015 unsigned warns=warn0.size(); 1016 char ch; 1017 for (unsigned i=0;i<warns;){ 1018 ch = warn0[i]; 1019 ++i; 1020 curline += ch; 1021 if (ch=='\n' || i==warns){ 1022 debutline=curline.substr(0,min(size_t(10),curline.size())); 1023 if (debutline!=gettext("// Parsing") && debutline!=gettext("// Success")) 1024 warn += curline; 1025 *old << curline; 1026 curline=""; 1027 } 1028 } 1029 // check if there is a parse error at end of input 1030 // if so then does like a event_shift 1031 if (giac::first_error_line(contextptr)){ 1032 string logs; 1033 int col=giac::lexer_column_number(contextptr); 1034 string token=giac::error_token_name(contextptr); 1035 logs = gettext("Syntax error in compatibility mode: ")+giac::print_program_syntax(giac::xcas_mode(contextptr))+"\n"; 1036 logs += gettext("Parse error line ")+giac::print_INT_(giac::first_error_line(contextptr))+ gettext(" column ")+giac::print_INT_(col) + gettext(" at ") ; 1037 if (!token.empty() && token[0]=='%') 1038 logs += token.substr(1,token.size()-1); 1039 else 1040 logs += token; 1041 const char * ch=value(); 1042 unsigned line=0,line_beg=0,line_end=0,taille=strlen(ch),i; 1043 for (i=0;i<taille;i++){ 1044 if (ch[i]=='\n'){ 1045 ++line; 1046 line_end=i; 1047 if (line==unsigned(giac::first_error_line(contextptr))) 1048 break; 1049 line_beg=i+1; 1050 } 1051 } 1052 if (line_beg+col>taille){ 1053 int ans=fl_ask("%s",((logs+'\n')+gettext("To get a newline, use shift-Enter. Reedit?")).c_str()); 1054 if (ans==1){ 1055 position(taille,taille); 1056 Fl::focus(this); 1057 handle(FL_FOCUS); 1058 // insert("\n"); 1059 // if (!tableur) increase_size(this,labelsize()+1); 1060 return 1; 1061 } 1062 } 1063 else { 1064 // position(line_beg,line_end); 1065 int ans=fl_ask("%s",(logs+"\nReedit?").c_str()); 1066 if (ans){ 1067 i=line_beg+col-1; 1068 position(max(int(i-token.size()),0),i); 1069 Fl::focus(this); 1070 handle(FL_FOCUS); 1071 return 1; 1072 } 1073 } 1074 } // if first_error_line 1075 else { 1076 // Correct parse, check for warnings 1077 if (warn.empty()){ 1078 _g=val; 1079 clear_changed(); 1080 } 1081 else 1082 fl_message("%s",warn.c_str()); 1083 } 1084 position(size(), 0); 1085 history.push_back(value()); 1086 count=history.size(); 1087 int pos=-1; 1088 History_Pack * hp=get_history_pack(this,pos); 1089 if (hp) 1090 hp->update_pos=pos; 1091 find_fold_autosave_function(true); 1092 do_callback(); 1093 return 1; 1094 } 1095 if (key==FL_Escape){ 1096 if (tableur && tableur->editing){ 1097 tableur->editing=false; 1098 Fl::focus(tableur); 1099 } 1100 else { 1101 Fl::selection(*this,value(),strlen(value())); 1102 value(""); 1103 } 1104 return 1; 1105 } 1106 if (key==FL_BackSpace){ 1107 const char * ch = value(); 1108 unsigned l=strlen(ch); 1109 unsigned p=position(); 1110 unsigned m=mark(); 1111 if (tableur && tableur->editing && !l){ 1112 tableur->editing=false; 1113 Fl::focus(tableur); 1114 return 1; 1115 } 1116 if (l && p && p==m && p<=l && ch[p-1]=='\n'){ 1117 if (!tableur) 1118 increase_size(this,-labelsize()-1); 1119 } 1120 } 1121 if (tableur){ 1122 tableur->editing=true; 1123 tableur->edit_row=tableur->row(); 1124 tableur->edit_col=tableur->col(); 1125 } 1126 if (g && !tableur && key==FL_Right && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){ 1127 int i=position(); 1128 if (i==size()) 1129 return 1; 1130 } 1131 if (g && !tableur && key==FL_Left && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){ 1132 int i=position(); 1133 if (!i) 1134 return 1; 1135 } 1136 if (g && !tableur && (key==FL_Up || key==FL_Page_Up) && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){ 1137 // if we are at the top line, go one level up 1138 int i=position(); 1139 if (i) 1140 i=line_start(i); 1141 if (!i || (key==FL_Page_Up) ){ 1142 redraw(); 1143 g->_sel_begin=-1; 1144 int pos=g->set_sel_begin(this); 1145 g->_sel_begin=-1; 1146 --pos; 1147 if (pos>=0) 1148 g->focus(pos,true); 1149 return 1; 1150 } 1151 } 1152 if (g && !tableur && (key==FL_Down || key==FL_Page_Down) && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){ 1153 // if we are at the top line, go one level up 1154 int i=position(); 1155 i=line_end(i); 1156 if (i>=size() || (key==FL_Page_Down) ){ 1157 redraw(); 1158 g->_sel_begin=-1; 1159 int pos=g->set_sel_begin(this)+1; 1160 g->_sel_begin=-1; 1161 g->focus(pos,true); 1162 return 1; 1163 } 1164 } 1165 if (key==FL_Up || key==FL_Down){ 1166 if (!Fl::event_state(FL_SHIFT |FL_CTRL | FL_ALT) && Fl_Multiline_Input::handle(event)){ 1167 match(); 1168 redraw(); 1169 return 1; 1170 } 1171 if (!Fl::event_state(FL_CTRL | FL_ALT)) 1172 return 0; 1173 // not handled by the input, use history 1174 int s=history.size(); 1175 Fl::focus(this); 1176 if (Fl::event_key()==FL_Up){ 1177 --count; 1178 if (count<0) 1179 count=0; 1180 } 1181 else { 1182 ++count; 1183 if (count>=s) 1184 count=max(0,s-1); 1185 } 1186 if (count<s){ 1187 string v(value()); 1188 int pos1=position(),pos2=mark(); 1189 if (pos1>pos2) 1190 giac::swapint(pos1,pos2); 1191 value((v.substr(0,pos1)+history[count]+v.substr(pos2,v.size()-pos2)).c_str()); 1192 position(pos1,pos1+history[count].size()); 1193 } 1194 set_changed(); 1195 return 1; 1196 } 1197 } 1198 if (!completion_tab || event!=FL_KEYBOARD || (Fl::event_text() && Fl::event_text()[0]!=9 && Fl::event_key()!=FL_F+1)){ 1199 const char * ch = value(); 1200 unsigned l=strlen(ch); 1201 unsigned p=position(); 1202 unsigned m=mark(); 1203 bool test_backspace=(l && p && p==m && p<=l && ch[p-1]=='\n') || (p!=m); 1204 int res=Fl_Multiline_Input::handle(event); 1205 if (event==FL_KEYBOARD && res ){ 1206 match(); 1207 redraw(); 1208 if ( test_backspace && Fl::event_key()==FL_BackSpace) 1209 resize_nl(); 1210 } 1211 return res; 1212 } 1213 string s(value()),ans; 1214 if (position()<int(s.size())) 1215 s=s.substr(0,position()); 1216 int delta=s.size(); 1217 s=motclef(s); 1218 delta -= s.size(); 1219 int remove; 1220 if (int ii=handle_tab(s,*completion_tab,window()->w(),window()->h()/3,remove,ans)){ 1221 window()->show(); 1222 cut(-remove-delta); 1223 if (ii==1){ 1224 insert((ans+"()").c_str()); 1225 position(size()-1); 1226 } 1227 else { 1228 insert(ans.c_str()); 1229 position(size()); 1230 } 1231 if (parent()) 1232 parent_redraw(parent()); 1233 } 1234 Fl::focus(this); 1235 handle(FL_FOCUS); 1236 return 1; 1237 } 1238 1239 /* void Multiline_Input_tab::draw(){ 1240 int pos=position(); 1241 int clip_x,clip_y,clip_w,clip_h; 1242 fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h); 1243 if (clip_w==0 || clip_h==0) 1244 return; 1245 // if (pos!=mark()){ 1246 Fl_Multiline_Input::draw(); 1247 return; 1248 // } 1249 } */ 1250 1251 // geo_print / geoprint _pnt2string(const giac::gen & g,const giac::context * contextptr)1252 std::string _pnt2string(const giac::gen & g,const giac::context * contextptr){ 1253 unsigned ta=taille(g,100); 1254 if (ta>100) 1255 return "Done"; 1256 if (g.is_symb_of_sommet(giac::at_pnt) && !is3d(g)){ 1257 giac::gen & f=g._SYMBptr->feuille; 1258 if (f.type==giac::_VECT && !f._VECTptr->empty()){ 1259 giac::gen f0=f._VECTptr->front(); 1260 if (f0.is_symb_of_sommet(giac::at_legende)){ 1261 return g.print(contextptr); 1262 } 1263 if (f0.is_symb_of_sommet(giac::at_curve)){ 1264 giac::gen f1=f[0]._SYMBptr->feuille; 1265 if (f1.type==giac::_VECT && !f1._VECTptr->empty() ){ 1266 giac::gen f1f=f1._VECTptr->front(); 1267 if (f1f.type==giac::_VECT && f1f._VECTptr->size()>=4){ 1268 giac::vecteur f1v=*f1f._VECTptr; 1269 return "plotparam("+pnt2string(f1v[0],contextptr)+","+f1v[1].print(contextptr)+"="+f1v[2].print(contextptr)+".."+f1v[3].print(contextptr)+")"; 1270 } 1271 } 1272 } 1273 if (f0.is_symb_of_sommet(giac::at_cercle) && f0._SYMBptr->feuille.type==giac::_VECT){ 1274 if (f0._SYMBptr->feuille._VECTptr->size()==3 && ((*f0._SYMBptr->feuille._VECTptr)[2]!=giac::cst_two_pi || (*f0._SYMBptr->feuille._VECTptr)[1]!=0)) 1275 return f0.print(contextptr); 1276 giac::gen centre,rayon; 1277 if (!giac::centre_rayon(f0,centre,rayon,true,0)) 1278 return "cercle_error"; 1279 if (!complex_mode(contextptr) && (centre.type<giac::_IDNT || centre.type==giac::_FRAC) ) 1280 return gettext("circle")+string("(point(")+giac::re(centre,contextptr).print(contextptr)+","+giac::im(centre,contextptr).print(contextptr)+"),"+rayon.print(contextptr)+")"; 1281 else 1282 return gettext("circle")+string("(point(")+centre.print(contextptr)+"),"+rayon.print(contextptr)+")"; 1283 } 1284 if (f0.type==giac::_VECT &&f0.subtype!=giac::_POINT__VECT){ 1285 std::string s=gettext("polygon")+string("("); 1286 giac::const_iterateur it=f0._VECTptr->begin(),itend=f0._VECTptr->end(); 1287 if ( itend-it==2){ 1288 switch(f0.subtype){ 1289 case giac::_LINE__VECT: 1290 s=gettext("line")+string("("); 1291 break; 1292 case giac::_HALFLINE__VECT: 1293 s=gettext("half_line")+string("("); 1294 break; 1295 case giac::_GROUP__VECT: 1296 s=gettext("segment")+string("("); 1297 break; 1298 } 1299 if (f0.subtype==giac::_LINE__VECT && it->type!=giac::_VECT){ // 2-d line 1300 s += _equation(g,contextptr).print(contextptr) + ")"; 1301 return s; 1302 } 1303 } 1304 for (;it!=itend;){ 1305 s += "point("; 1306 if (!complex_mode(contextptr) && (it->type<giac::_IDNT || it->type==giac::_FRAC) ) 1307 s += giac::re(*it,contextptr).print(contextptr)+","+giac::im(*it,contextptr).print(contextptr); 1308 else 1309 s+=it->print(contextptr); 1310 s+=")"; 1311 ++it; 1312 s += it==itend?")":","; 1313 } 1314 return s; 1315 } 1316 if ( (f0.type!=giac::_FRAC && f0.type>=giac::_IDNT) || is3d(g) || complex_mode(contextptr)) 1317 return "point("+f0.print(contextptr)+")"; 1318 else 1319 return "point("+giac::re(f0,contextptr).print(contextptr)+","+giac::im(f0,contextptr).print(contextptr)+")"; 1320 } 1321 } 1322 if (g.type==giac::_VECT && !g._VECTptr->empty() && g._VECTptr->back().is_symb_of_sommet(giac::at_pnt)){ 1323 std::string s = "["; 1324 giac::const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); 1325 for (;it!=itend;){ 1326 s += pnt2string(*it,contextptr); 1327 ++it; 1328 s += it==itend?"]":","; 1329 } 1330 return s; 1331 } 1332 return g.print(contextptr); 1333 } 1334 pnt2string(const giac::gen & g,const giac::context * contextptr)1335 std::string pnt2string(const giac::gen & g,const giac::context * contextptr){ 1336 try { 1337 return _pnt2string(g,contextptr); 1338 } 1339 catch (...){ 1340 return "conversion error"; 1341 } 1342 } 1343 value(const giac::gen & _g)1344 void Gen_Output::value(const giac::gen & _g){ 1345 g=_g; 1346 Fl_Multiline_Output::value(pnt2string(g,get_context(this)).c_str()); 1347 } 1348 value(const char * ch)1349 void Gen_Output::value(const char * ch){ 1350 giac::context * contextptr=get_context(this); 1351 g=giac::gen(ch,contextptr); 1352 Fl_Multiline_Output::value(ch); 1353 } 1354 value() const1355 giac::gen Gen_Output::value() const { 1356 return g; 1357 } 1358 set_g(const giac::gen & g)1359 void Multiline_Input_tab::set_g(const giac::gen & g) { 1360 const giac::context * contextptr = get_context(this); 1361 value(g.print(contextptr).c_str()); 1362 redraw(); 1363 clear_changed(); 1364 _g=g; 1365 } 1366 g()1367 giac::gen Multiline_Input_tab::g() { 1368 if (!changed()) 1369 return _g; 1370 giac::context * contextptr=get_context(this); 1371 _g=giac::gen(value(),contextptr); 1372 clear_changed(); 1373 return _g; 1374 } 1375 value(const char * ch)1376 void Enlargable_Multiline_Output::value(const char * ch){ 1377 Fl_Multiline_Output::value(ch); 1378 resize(); 1379 } 1380 resize()1381 void Enlargable_Multiline_Output::resize(){ 1382 // Count number of \n 1383 const char * ch=Fl_Multiline_Output::value(); 1384 int n=strlen(ch); 1385 int h0=labelsize(),res=n?h0+4:1; 1386 int j=0,nc=0,nl=0; 1387 string temp=""; 1388 fl_font(textfont(),labelsize()); 1389 for (int i=0;i<n;++i,++ch){ 1390 if (*ch=='\n'){ 1391 res += h0+1; 1392 nc=max(nc,j); 1393 j=0; 1394 nl=max(nl,int(fl_width(temp.c_str()))); 1395 temp =""; 1396 } 1397 else { 1398 j++; 1399 temp += *ch; 1400 } 1401 } 1402 nl+=6; 1403 if (parent()){ 1404 int w=parent()->w(); 1405 int h=parent()->h(); 1406 if (res<h-6) 1407 res=h-6; 1408 if (nl<w-labelsize()) 1409 nl=w-labelsize(); 1410 parent()->redraw(); 1411 } 1412 Fl_Multiline_Output::resize(x(),y(),nl,res); 1413 } 1414 handle(int event)1415 int Comment_Multiline_Input::handle(int event){ 1416 string oldval(value()); 1417 int res=in_handle(event); 1418 History_Pack * g=get_history_pack(this); 1419 if (g && value()!=oldval) 1420 g->modified(false); 1421 return res; 1422 } 1423 in_handle(int event)1424 int Comment_Multiline_Input::in_handle(int event){ 1425 if (event==FL_FOCUS){ 1426 Xcas_input_focus=this; 1427 autosave_disabled=false; 1428 // Fl::focus(this); 1429 // redraw(); 1430 return Fl_Multiline_Input::handle(event); 1431 } 1432 if (event==FL_UNFOCUS){ 1433 return Fl_Multiline_Input::handle(event); 1434 } 1435 if (event==FL_KEYBOARD){ 1436 redraw(); 1437 int key=Fl::event_key(); 1438 if ( (key==FL_Enter || key==FL_KP_Enter) 1439 && Fl::event_shift()){ 1440 insert("\n"); 1441 increase_size(this,labelsize()+2); 1442 return 1; 1443 } 1444 if (key==FL_BackSpace){ 1445 const char * ch = value(); 1446 unsigned l=strlen(ch); 1447 unsigned p=position(); 1448 unsigned m=mark(); 1449 if (l && p && p==m && p<=l && ch[p-1]=='\n'){ 1450 increase_size(this,-labelsize()-2); 1451 } 1452 } 1453 History_Pack * hp = get_history_pack(this); 1454 int change_focus=0; 1455 if (hp && ( (key==FL_Up && !line_start(position())) || key==FL_Page_Up)) 1456 change_focus=-1; 1457 if (hp && ( (key==FL_Down && line_end(position())==size()) || key==FL_Page_Down || key==FL_Enter)) 1458 change_focus=1; 1459 if (key==FL_Enter){ 1460 string s=value(); 1461 s+=' '; 1462 // search in s for a word with ., check if it's an existing filename or URL 1463 int ss=s.size(); 1464 for (int i=0;i<ss;++i){ 1465 if (s[i]==' ') 1466 continue; 1467 int wordbegin=i; 1468 bool haspoint=false; 1469 // begin of word 1470 for (++i;i<ss;++i){ 1471 if (s[i]=='.' && 1472 i<ss-1 && s[i+1]>='a' && s[i+1]<='z' && 1473 i && (isalpha(s[i-1]) || (s[i-1]>='0' && s[i-1]<='9')) 1474 ) 1475 haspoint=true; 1476 if (s[i]==' ') 1477 break; 1478 } 1479 if (!haspoint) 1480 continue; 1481 string url; 1482 if (i>wordbegin+8 && (s.substr(wordbegin,8)=="https://" || s.substr(wordbegin,7)=="http://" || s.substr(wordbegin,7)=="file://")){ 1483 url=s.substr(wordbegin,i-wordbegin); 1484 } 1485 else { 1486 if (s[wordbegin]=='@'){ 1487 url=s.substr(wordbegin+1,i-wordbegin-1); 1488 } 1489 } 1490 if (url.empty()) 1491 continue; 1492 if (giac::is_file_available(url.c_str())){ 1493 if (url[0]!='/') 1494 url=*giac::_pwd(0,0)._STRNGptr+"/"+url; 1495 } 1496 else { 1497 if (url.size()<8 || (url.substr(0,8)!="https://" && url.substr(0,7)!="http://" && url.substr(0,7)!="file://")) 1498 url="http://"+url; 1499 } 1500 giac::system_browser_command(url); 1501 // break; 1502 } 1503 } 1504 if (change_focus && hp){ 1505 hp->_sel_begin=-1; 1506 int pos=hp->set_sel_begin(this); 1507 if (pos+change_focus>=0) 1508 hp->focus(pos+change_focus,true); 1509 return 1; 1510 } 1511 } 1512 return Fl_Multiline_Input::handle(event); 1513 } 1514 1515 #ifndef NO_NAMESPACE_XCAS 1516 } // namespace xcas 1517 #endif // ndef NO_NAMESPACE_XCAS 1518 1519 1520 #endif // HAVE_LIBFLTK 1521