// -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -g -c Input.cc -Wall" -*-
/*
* Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef IN_GIAC
#include
#else
#include "first.h"
#endif
#include
#ifdef HAVE_LIBFLTK
#include "Input.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "History.h"
#include "Xcas1.h"
#include "Tableur.h"
#include "Graph3d.h"
#include "Help1.h"
#ifndef IN_GIAC
#include
#include
#include
#else
#include "plot.h"
#include "help.h"
#include "global.h"
#endif
#include
#include
#ifdef HAVE_UNISTD_H
#include
#endif
using namespace std;
#ifndef NO_NAMESPACE_XCAS
namespace xcas {
#endif // ndef NO_NAMESPACE_XCAS
#define TAB_ARGS 6
#if defined __APPLE__ || defined WIN32
bool use_external_browser = true ;
#else
bool use_external_browser = getenv("BROWSER") ;
#endif
std::vector Multiline_Input_tab::history;
int Multiline_Input_tab::count=0;
Fl_Help_Dialog * Xcas_help_window = new Fl_Help_Dialog();
Fl_Widget * Xcas_input_focus=0;
void system_browser(const string & s){
int i=giac::system_no_deprecation(s.c_str());
if (i!=0){
fl_alert("%s",("Switching to internal browser, error running browser command "+s).c_str());
use_external_browser=false;
}
}
bool read_aide(const string & progname,int language){
string helpfile("aide_cas");
int helpitems=0;
(*giac::vector_aide_ptr())=giac::readhelp(helpfile.c_str(),helpitems,false);
if (!helpitems){
if (getenv("XCAS_HELP"))
helpfile=getenv("XCAS_HELP");
else
helpfile=giac::giac_aide_dir()+"aide_cas";
(*giac::vector_aide_ptr())=giac::readhelp(helpfile.c_str(),helpitems);
}
if (!helpitems){
cerr << "// Unable to open help file "<< helpfile << endl;
return false;
}
else {
cerr << "// Using help file " << helpfile << endl;
giac::xcasroot()=giac::xcasroot_dir((char *) progname.c_str());
/* patch for gsview TEMP, but does not work
if (!getenv("TEMP")){
if (giac::is_file_available("/tmp"))
setenv("TEMP","/tmp",1);
else
setenv("TEMP",giac::xcasroot().c_str(),1);
}
*/
cerr << "// root dir " << giac::xcasroot() << endl;
giac::html_help_init((char *) progname.c_str(),language);
giac::update_completions();
return true;
}
}
// return the last keyword of s
std::string motclef(const std::string & s){
int l=s.size();
int i=l-1;
for (;i>=0;i--){
if (giac::isalphan(s[i]))
break;
}
l=i+1;
for (;i>=0;i--){
if (!giac::isalphan(s[i]))
return s.substr(i+1,l-1-i);
}
return s.substr(0,l);
}
string findtooltip(const giac::gen & g){
string s,s1,s2;
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",};
static const char * tooltip_name[]={"Intg","Expr","Var","Mtrx","Fnc","Str","Poly","Vect","Pnt","Lst","LstPnt","LstReal","LstIntg","SeqVar","Cmd",0};
if (g.is_symb_of_sommet(giac::at_ou)){
giac::gen & f = g._SYMBptr->feuille;
if (f.type==giac::_VECT){
giac::const_iterateur it=f._VECTptr->begin(),itend=f._VECTptr->end();
if (it!=itend){
for (s=findtooltip(*it),++it;it!=itend;++it)
s = s + gettext(" or ") + findtooltip(*it);
}
}
return s;
}
if (g.type==giac::_VECT && g._VECTptr->size()==1)
return findtooltip(g._VECTptr->front())+"(optional)";
s = g.print(giac::context0);
int l=s.size();
int p=s.find('(');
if (p>0 && plabelfont(),w->labelsize());
string res,ajout;
int fin=s.size(),debut=0;
int taille=w->w();
for (;debut0;--l){
if (s[debut+l]==' '){
ajout=s.substr(debut,l);
if (fl_width(ajout.c_str())<=taille){
res += ajout;
res += '\n';
break;
}
}
}
if (l==0)
return res+ajout;
debut += l+1;
}
return res;
}
void update_examples(const string & s,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language){
help_output(s,language);
if (output->label())
delete output->label();
char * ptr=new char [s.size()+1];
strcpy(ptr,s.c_str());
output->label(ptr);
if (output->parent())
output->parent()->redraw();
if (examples && output ){
giac::aide cur_aide=giac::helpon(s,(*giac::vector_aide_ptr()),language,(*giac::vector_aide_ptr()).size(),false);
string result=cur_aide.cmd_name;
if (!cur_aide.syntax.empty()){
result=result+"("+cur_aide.syntax+")\n";
giac::gen helpg;
giac::vecteur helpv;
if (!cur_aide.syntax.empty()){
helpg=giac::gen(cur_aide.syntax,giac::context0);
if (helpg.type==giac::_VECT)
helpv=*helpg._VECTptr;
else
helpv=giac::vecteur(1,helpg);
}
giac::const_iterateur jt=helpv.begin(),jtend=helpv.end();
Fl_Input ** ptr=argtab, ** argtabend=argtab+TAB_ARGS;
if (jtend-jt>TAB_ARGS)
jtend=jt+TAB_ARGS;
for (;*ptr && jt!=jtend;++jt,++ptr){
giac::gen tmp=*jt;
string tmps=tmp.print(giac::context0);
if (tmp.type==giac::_VECT)
(*ptr)->labelcolor(FL_BLUE);
else
(*ptr)->labelcolor(FL_BLACK);
if ((*ptr)->label())
free((void *) (*ptr)->label());
char * chartab = (char *) malloc(sizeof(char)*(tmps.size()+1));
strcpy(chartab,tmps.c_str());
(*ptr)->label(chartab);
(*ptr)->show();
(*ptr)->value("");
tmps = findtooltip(tmp);
if ((*ptr)->tooltip())
free((void *) (*ptr)->tooltip());
char * chartab2 = (char *) malloc(sizeof(char)*(tmps.size()+1));
strcpy(chartab2,tmps.c_str());
(*ptr)->tooltip(chartab2);
}
int L=output->labelsize()+2;
int eh=L*((1+(ptr-argtab))/2);
int outputyh = output->y()+output->h();
examples->resize(examples->x(),outputyh+eh,examples->w(),examples->parent()->h()-outputyh-eh-2);
for (;ptr!=argtabend;++ptr){
if (*ptr)
(*ptr)->hide();
}
}
vector::const_iterator it=cur_aide.blabla.begin(),itend=cur_aide.blabla.end();
for (;it!=itend;++it){
if (it->language==language){
result = split(it->chaine,output) +'\n'+result ;
break;
}
}
output->value(result.c_str());
examples->clear();
examples->add(s.c_str());
std::vector::const_iterator jt=cur_aide.examples.begin(),jtend=cur_aide.examples.end();
for (;jt!=jtend;++jt)
examples->add(jt->c_str());
related->clear();
syns->clear();
std::vector::const_iterator kt=cur_aide.related.begin(),ktend=cur_aide.related.end();
for (;kt!=ktend;++kt){
string tmp=giac::localize(kt->chaine,language);
related->add(tmp.c_str());
}
std::vector::const_iterator lt=cur_aide.synonymes.begin(),ltend=cur_aide.synonymes.end();
for (;lt!=ltend;++lt){
if (lt->chaine!=s)
syns->add(lt->chaine.c_str());
}
}
}
void handle_tab_cb_browser(Fl_Browser * b,void *){
int k=b->value();
if (k>=1){
string s=b->text(k);
// find examples browser
Fl_Group * g = b->parent();
Fl_Browser * examples=0, * related=0,*syns=0;
Fl_Output * output=0;
Fl_Input * input=0,*argtab[TAB_ARGS]={0,0,0,0,0,0};
if (g){
int n=g->children();
for (int i=0;i4 && (output=dynamic_cast(g->child(i)))){
related=dynamic_cast(g->child(i-4));
syns=dynamic_cast(g->child(i-3));
examples=dynamic_cast(g->child(i+7));
input=dynamic_cast(g->child(i-1));
for (int k=0;k(g->child(i+1+k));
}
break;
}
}
}
if (output && input && examples && related && syns){
update_examples(s,examples,related,syns,output,argtab,giac::language(giac::context0));
input->value(b->text(k));
if (Fl::event_clicks()){
g->hide();
}
}
else
help_output(s,giac::language(giac::context0));
}
}
void browser_html_help(Fl_Browser * b,Fl_Browser * examples,Fl_Browser * related,Fl_Browser * syns,Fl_Output * output,Fl_Input ** argtab,int language){
int k=b->value();
if (k>=1){
if (Xcas_help_window){
string s=b->text(k);
update_examples(s,examples,related,syns,output,argtab,language);
std::map::const_iterator it=giac::lexer_localization_map().find(s),itend=giac::lexer_localization_map().end();
if (it!=itend)
s=it->second;
vector v=giac::html_help(giac::html_mtt,s);
if (!v.empty()){
if (use_external_browser)
giac::system_browser_command(v.front());
else {
Xcas_help_window->load(v.front().c_str());
if (!xcas::Xcas_help_window->visible())
xcas::Xcas_help_window->show();
}
}
}
b->window()->show();
Fl::focus(b);
}
}
Fl_Window * handle_tab_w = 0;
// Find a completion of s in v -> ans, return true if user OK
// dx,dy=size of browser window
int handle_tab(const string & s,const vector & v,int dx,int dy,int & remove,string & ans,bool allow_immediate_out){
static Fl_Hold_Browser * browser = 0;
static Fl_Hold_Browser * related = 0;
static Fl_Hold_Browser * syns = 0;
static Fl_Button * button0 = 0 ;
static Fl_Button * button1 =0;
static Fl_Button * button2 =0;
static Fl_Button * topic_help=0;
static Fl_Input * input = 0;
static Fl_Multiline_Output * output = 0;
static Fl_Hold_Browser * examples = 0;
static Fl_Input * argtab[TAB_ARGS]={0,0,0,0,0,0};
int L=16;
const giac::context * contextptr=giac::context0;
if (xcas::Xcas_input_focus && xcas::Xcas_input_focus->window()){
dx=4*xcas::Xcas_input_focus->window()->w()/5;
dy=4*xcas::Xcas_input_focus->window()->h()/5;
L=xcas::Xcas_input_focus->labelsize()+2;
contextptr=get_context(xcas::Xcas_input_focus);
}
else {
if (dx>500)
dx=500;
}
if (dy<300)
dy=300;
if (dx<240)
dx=240;
// search non ascii char in s starting from the end
int ss=s.size();
string res;
remove=0;
for (int i=ss-1;i>=0;--i,++remove){
const char & ch =s[i];
if (giac::isalphan(ch) || ch=='&' || ch=='|' || ch=='=' || ch==':' || ch=='@' || ch=='<' || ch=='>' || ch=='+' || ch=='-' || ch=='/' || ch=='*' || ch=='$' || ch=='%')
res=ch+res;
else {
if (!res.empty())
break;
}
}
ss=res.size();
if (!handle_tab_w){
Fl_Group::current(0);
handle_tab_w=new Fl_Window(50,100,dx,dy,gettext("Index"));
button0 = new Fl_Button(2,2,dx/3-4,L+2);
button0->shortcut(0xff0d);
button0->label(gettext("OK"));
button0->tooltip(gettext("Click to copy the commandname to the commandline"));
button1 = new Fl_Button(dx/3+2,2,dx/3-4,L+2);
button1->shortcut(0xff1b);
button1->label(gettext("Cancel"));
button2 = new Fl_Button(2*dx/3+2,2,dx/3-4,L+2);
button2->label(gettext("Details"));
button2->tooltip(gettext("Show full HTML help in browser"));
browser = new Fl_Hold_Browser(2,2*L+4,dx/2-2,dy/2-(2*L+4));
browser->format_char(0);
browser->type(2);
browser->label(gettext("Index"));
browser->align(FL_ALIGN_TOP);
browser->callback((Fl_Callback*)handle_tab_cb_browser);
// order is important: related,syns, examples,input,output
related = new Fl_Hold_Browser(dx/2+2,2*L+4,dx/2-2,dy/4-(L+2));
related->label(gettext("Related"));
related->format_char(0);
related->align(FL_ALIGN_TOP);
related->tooltip(gettext("Click for help on related command"));
syns = new Fl_Hold_Browser(dx/2+2,related->y()+related->h()+L+2,dx/2-2,dy/4-(2*L+4));
syns->format_char(0);
syns->label(gettext("Synonyms"));
syns->align(FL_ALIGN_TOP);
topic_help = new Fl_Button(0,browser->y()+browser->h(),L,L+4);
topic_help->label("?");
topic_help->tooltip(gettext("Search this word in HTML help"));
input = new Fl_Input(L,browser->y()+browser->h(),dx-L,L+4);
input->when(FL_WHEN_CHANGED |FL_WHEN_ENTER_KEY |FL_WHEN_NOT_CHANGED);
// input->label("?");
input->tooltip(gettext("Show commandnames starting from this text"));
output = new Fl_Multiline_Output(2,input->y()+input->h(),dx-4,3*L+9);
output->tooltip(gettext("Command short description and syntax"));
// arguments
int ypos=output->y()+output->h();
for (int j=0;jwhen(FL_WHEN_ENTER_KEY |FL_WHEN_NOT_CHANGED);
}
ypos += 3*L;
examples = new Fl_Hold_Browser(output->x(),ypos,output->w(),handle_tab_w->h()-output->y()-output->h()-2-3*L);
examples->label("Examples");
examples->type(2);
examples->align(FL_ALIGN_LEFT);
examples->tooltip(gettext("Left-click: copy example to commandline, right-click: fill in template with example values"));
handle_tab_w->end();
handle_tab_w->resizable(handle_tab_w);
change_group_fontsize(handle_tab_w,L-2);
}
else {
browser->clear();
examples->clear();
related->clear();
}
if (ss)
input->value(res.c_str());
else {
res=input->value();
ss=res.size();
allow_immediate_out=false;
}
input->position(ss,ss);
vector vres;
int vs=v.size(),i=0,r=-1,i_=0;
for (int k=0;kadd(v[k].c_str());
if (!i && v[k].substr(0,ss)==res){
i=k+1;
}
if (v[k][0]==res[0]){
i_=k+1;
}
}
if (!i){
if (allow_immediate_out)
return 0;
else
i=i_;
if (!i)
i=1;
}
handle_tab_w->set_modal();
if (vs){
browser->value(i);
string bt=browser->text(i);
update_examples(bt,examples,related,syns,output,argtab,giac::language(contextptr));
handle_tab_w->show();
handle_tab_w->hotspot(handle_tab_w);
Fl::focus(input);
for (;;) {
if (!handle_tab_w->shown()){
r=0; break;
}
Fl_Widget *o = Fl::readqueue();
if (!o) Fl::wait();
else {
if (o == topic_help){ help_fltk(input->value()); }
if (o == button0) {r = 0; break;}
if (o == button1) {r = 1; break;}
if (o == button2) browser_html_help(browser,examples,related,syns,output,argtab,giac::language(contextptr));
int j=0;
for (;jvalue()[0];
break;
}
}
if (j!=TAB_ARGS){ r=0; break; }
if ( o == examples && examples->value() ) {
string tmp=examples->text(examples->value());
if (Fl::event_button()!=3 || (!tmp.empty() && tmp[0]==' ')){
r=2;
break;
}
giac::gen tmpg(tmp,contextptr);
if (browser->value()>=1 && tmpg.type==giac::_SYMB && tmpg._SYMBptr->sommet==giac::gen(browser->text(browser->value()),contextptr))
tmpg=tmpg._SYMBptr->feuille;
giac::vecteur v;
if (tmpg.type==giac::_VECT && tmpg.subtype==giac::_SEQ__VECT)
v=*tmpg._VECTptr;
else
v=giac::vecteur(1,tmpg);
int vs=v.size();
for (int j=0;jvalue(v[j].print(contextptr).c_str());
}
}
if ( o == related && related->value() ) {
string s=related->text(related->value());
update_examples(s,examples,related,syns,output,argtab,giac::language(contextptr));
for (i=0;ivalue(i+1);
break;
}
}
}
if ( o == syns && syns->value() ) {
string s=syns->text(syns->value());
update_examples(s,examples,related,syns,output,argtab,giac::language(contextptr));
for (i=0;ivalue(i+1);
break;
}
}
}
if (o == handle_tab_w) { r=1; break; }
if (o == input){
if (Fl::event_key(FL_Enter) || Fl::event_key(FL_KP_Enter)){
if (Fl::event_state(FL_SHIFT |FL_CTRL | FL_ALT)){
Fl::focus(examples);
browser_html_help(browser,examples,related,syns,output,argtab,giac::language(contextptr));
}
else {
r=0;
break;
}
}
else {
const char * entree=input->value();
char nentree[256]; nentree[255]=0;
char nch[256]; nentree[255]=0;
for (int j=0;j<255;++j){
nentree[j]=tolower(entree[j]);
if (!entree[j]) break;
}
for (i=1;i<=vs;++i){
const char * ch=browser->text(i);
for (int j=0;j<255;++j){
nch[j]=tolower(ch[j]);
if (!ch[j]) break;
}
if (ch){
int comp=strcmp(nch,nentree);
if (!comp)
comp=strcmp(ch,entree);
if (comp>=0)
break;
}
}
if (i<=vs){
browser->value(i);
update_examples(browser->text(i),examples,related,syns,output,argtab,giac::language(contextptr));
}
}
}
}
}
/* does not work properly, since focus might change
if (foc && foc->window())
foc->window()->show();
else
*/
handle_tab_w->hide();
// Xcas_help_window->hide();
i=browser->value();
}
// delete browser;
// delete button1;
// delete button0;
// delete w;
int j=examples->value(); // ,k=related->value();
if (r==2 && j<=examples->size() && j>0){
ans=examples->text(j);
return 2;
}
if (r==0 && i<=vs && i>0){
ans=vres[i-1];
string addans;
Fl_Input ** ptr=argtab;
if (ptr && *ptr && (*ptr)->visible()){
addans = "(";
for (int j=0;*ptr && jvalue();
if (tmp.empty())
continue;
addans += tmp;
++ptr;
if (!(*ptr)->visible())
break;
addans += ",";
}
if (addans[addans.size()-1]==',')
addans=addans.substr(0,addans.size()-1);
addans += ")";
}
if (addans.size()>2){
ans += addans;
return 2;
}
return 1;
}
else
return 0;
}
void Multiline_Input_tab::insert_replace(const string & chaine,bool selected){
size_t pos1=position();
size_t pos2=mark();
if (pos1>pos2){
size_t tmp=pos1;
pos1=pos2;
pos2=tmp;
}
string input_s(value()),new_input;
size_t l=input_s.size();
new_input=input_s.substr(0,pos1)+chaine;
if (pos2handle(FL_ENTER);
}
Multiline_Input_tab::Multiline_Input_tab(int x,int y,int w,int h,const char * l):
Fl_Multiline_Input(x, y, w, h, l),handling(false),completion_tab(giac::vector_completions_ptr()),tableur(0),_g(giac::undef) {
if (parent()){
labelfont(parent()->labelfont());
labelsize(parent()->labelsize());
textfont(parent()->labelfont());
textsize(parent()->labelsize());
}
Fl_Widget::callback(Multiline_default_callback); parent_redraw(this);
when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
color(FL_WHITE);
textfont(FL_TIMES);
}
Comment_Multiline_Input::Comment_Multiline_Input(int x,int y,int w,int h,const char * l):
Fl_Multiline_Input(x,y,w,h,l) {
if (parent()){
labelfont(parent()->labelfont());
labelsize(parent()->labelsize());
textfont(parent()->labelfont());
textsize(parent()->labelsize());
}
parent_redraw(this);
color(FL_WHITE);
}
void Multiline_Input_tab::match(){
static bool recursive_call=false;
if (mark()!=position())
return;
int lastkey=Fl::event_key();
if (lastkey!='(' && lastkey!='[' && lastkey!='{' && lastkey!='}' && lastkey!=']' && lastkey!=')' && lastkey!='0' && lastkey!='9' && lastkey!='\'' && lastkey != '=' && lastkey !=FL_Left && lastkey !=FL_Right)
return;
if (recursive_call)
return;
recursive_call=true;
// check if cursor is on [, (, ), ]
int pos=position(),p0=pos;
const char * c=value();
int pmax=string(c).size();
bool closing=false,opening=false;
if (posmodified(false);
handling=false;
return res;
}
bool is_text_a_level(const char * ch){
unsigned l=strlen(ch),i;
char cmp[]="// fltk ";
for (i=0;ih()<=wid->labelsize()+4)
L=wid->labelsize()+5-wid->h();
int pos;
History_Pack * g = get_history_pack(wid,pos);
if (g){
Fl_Group * gr=wid->parent();
// find parents to above history pack
std::vector parents(1,wid);
for (;gr && gr!=g;gr=gr->parent()){
parents.push_back(gr);
}
Fl_Widget * tmp=0,*tmp2;
Fl_Group * tmpg=0;
int i=parents.size()-1;
for (;i>=0;--i){
tmpg=gr;
tmp=parents[i];
// move children of gr below tmp
int k=tmpg->children();
for (int j=0;jchild(j);
if (tmp2->y()>tmp->y()){
tmp2->resize(tmp2->x(),tmp2->y()+L,tmp2->w(),tmp2->h());
tmp2->redraw();
}
else {
if (tmp2==tmp){
tmp->Fl_Widget::resize(tmp->x(),tmp->y(),tmp->w(),tmp->h()+L);
tmp->redraw();
gr=dynamic_cast(tmp);
}
}
} // end for j
} // end for i
// recompute pack
g->resize();
g->redraw();
}
}
void Multiline_Input_tab::resize_nl(){
if (tableur)
return;
const char * ch = value();
unsigned i=0,l=strlen(ch),nl=1;
for (;i=0;--i0){
if (ch[i0]=='\n')
break;
}
string s=string(ch).substr(i0+1,i-i0-1);
fl_font(textfont(),textsize());
int lw=int(1.2*fl_width(s.c_str()));
return lw>w()+20;
}
int height(const char * ch,int labelsize){
int n=strlen(ch);
int h0=labelsize+4,res=n?h0+2:1;
int maxh=300;
for (int i=0;imaxh)
break;
}
}
return res;
}
int Multiline_Input_tab::in_handle(int event){
History_Pack * g=get_history_pack(this);
if (g && event==FL_MOUSEWHEEL){
if (!Fl::event_inside(this))
return 0;
if (Fl_Scroll * sc = dynamic_cast(g->parent())){
int scy=sc->yposition()+labelsize()*Fl::e_dy;
if (scy<0)
scy=0;
#ifdef _HAVE_FL_UTF8_HDR_
sc->scroll_to(sc->xposition(),scy);
#else
sc->position(sc->xposition(),scy);
#endif
return 1;
}
}
if (event==FL_FOCUS || event==FL_PUSH || event==FL_KEYBOARD){
Xcas_input_focus=this;
autosave_disabled=false;
}
if (event==FL_FOCUS){
// Fl::focus(this);
// redraw();
return Fl_Multiline_Input::handle(event);
}
if (event==FL_UNFOCUS){
return Fl_Multiline_Input::handle(event);
}
if (event==FL_PUSH && tableur)
tableur->editing=true;
if (g && event==FL_PASTE){
// check that it's not a // fltk ... pasting a full level
const char * ch=Fl::event_text();
if (ch){
if (is_text_a_level(ch))
return g->handle(event);
}
if (Fl_Multiline_Input::handle(event)){
if (!tableur){
// add space for ch
unsigned i=0,l=strlen(ch),nl=0;
for (;ieval();
return 1;
}
if (Fl::event_text()){
int i=Fl::event_text()[0];
switch (i){
case 22: case 25:
// Ctrl-V or Ctrl-Y paste, no need to check for level text
// because they paste using an FL_PASTE event
case 3: case 4: case 5: case 21: case 23: case 24: case 26:
if (Fl_Multiline_Input::handle(event)){
resize_nl();
return 1;
}
break;
case 1:
position(0);
mark(size());
Fl::selection(*this,value(),strlen(value()));
return 1;
case 2:
insert("[]");
position(position()-1,position()-1);
return 1;
case 11:
insert("\n");
resize_nl();
return 1;
case 12:
insert("{}");
position(position()-1,position()-1);
return 1;
case ' ': case ',': case '+':
if (need_nl()){
Fl_Multiline_Input::handle(event);
insert("\n");
resize_nl();
return 1;
}
break;
#ifndef __APPLE__
case '(':
// Fl::belowmouse(this);
str=motclef(string(value()).substr(0,position()));
if (!str.empty()){
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));
tooltip(toolt.c_str());
int hh=height(toolt.c_str(),Fl_Tooltip::size());
Fl_Tooltip::enter_area(this,0,-hh,0,0,toolt.c_str());
}
break;
case ')':
tooltip("");
break;
#endif
}
}
if (key==FL_Enter || key==FL_KP_Enter){
if (Fl::event_shift() || strlen(value())==0){
insert("\n");
if (!tableur)
increase_size(this,labelsize()+1);
return 1;
}
giac::gen val;
// keep warnings
giac::context * contextptr=g?g->contextptr:0;
ostringstream warnings ;
#ifdef WITH_MYOSTREAM
giac::my_ostream * old=giac::logptr(contextptr);
giac::my_ostream newptr(&warnings);
logptr(&newptr,contextptr);
#else
my_ostream * old=giac::logptr(contextptr);
logptr(&warnings,contextptr);
#endif
giac::first_error_line(contextptr)=0;
try {
val=warn_equal(giac::gen(value(),contextptr),contextptr);
}
catch (...){
;
}
string warn0=warnings.str(),curline,debutline;
giac::logptr(old,contextptr);
static string warn;
warn="";
// Read warn0 lines and skip Parsing and Success in warn
unsigned warns=warn0.size();
char ch;
for (unsigned i=0;itaille){
int ans=fl_ask("%s",((logs+'\n')+gettext("To get a newline, use shift-Enter. Reedit?")).c_str());
if (ans==1){
position(taille,taille);
Fl::focus(this);
handle(FL_FOCUS);
// insert("\n");
// if (!tableur) increase_size(this,labelsize()+1);
return 1;
}
}
else {
// position(line_beg,line_end);
int ans=fl_ask("%s",(logs+"\nReedit?").c_str());
if (ans){
i=line_beg+col-1;
position(max(int(i-token.size()),0),i);
Fl::focus(this);
handle(FL_FOCUS);
return 1;
}
}
} // if first_error_line
else {
// Correct parse, check for warnings
if (warn.empty()){
_g=val;
clear_changed();
}
else
fl_message("%s",warn.c_str());
}
position(size(), 0);
history.push_back(value());
count=history.size();
int pos=-1;
History_Pack * hp=get_history_pack(this,pos);
if (hp)
hp->update_pos=pos;
find_fold_autosave_function(true);
do_callback();
return 1;
}
if (key==FL_Escape){
if (tableur && tableur->editing){
tableur->editing=false;
Fl::focus(tableur);
}
else {
Fl::selection(*this,value(),strlen(value()));
value("");
}
return 1;
}
if (key==FL_BackSpace){
const char * ch = value();
unsigned l=strlen(ch);
unsigned p=position();
unsigned m=mark();
if (tableur && tableur->editing && !l){
tableur->editing=false;
Fl::focus(tableur);
return 1;
}
if (l && p && p==m && p<=l && ch[p-1]=='\n'){
if (!tableur)
increase_size(this,-labelsize()-1);
}
}
if (tableur){
tableur->editing=true;
tableur->edit_row=tableur->row();
tableur->edit_col=tableur->col();
}
if (g && !tableur && key==FL_Right && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){
int i=position();
if (i==size())
return 1;
}
if (g && !tableur && key==FL_Left && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){
int i=position();
if (!i)
return 1;
}
if (g && !tableur && (key==FL_Up || key==FL_Page_Up) && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){
// if we are at the top line, go one level up
int i=position();
if (i)
i=line_start(i);
if (!i || (key==FL_Page_Up) ){
redraw();
g->_sel_begin=-1;
int pos=g->set_sel_begin(this);
g->_sel_begin=-1;
--pos;
if (pos>=0)
g->focus(pos,true);
return 1;
}
}
if (g && !tableur && (key==FL_Down || key==FL_Page_Down) && !Fl::event_state(FL_SHIFT | FL_CTRL | FL_ALT)){
// if we are at the top line, go one level up
int i=position();
i=line_end(i);
if (i>=size() || (key==FL_Page_Down) ){
redraw();
g->_sel_begin=-1;
int pos=g->set_sel_begin(this)+1;
g->_sel_begin=-1;
g->focus(pos,true);
return 1;
}
}
if (key==FL_Up || key==FL_Down){
if (!Fl::event_state(FL_SHIFT |FL_CTRL | FL_ALT) && Fl_Multiline_Input::handle(event)){
match();
redraw();
return 1;
}
if (!Fl::event_state(FL_CTRL | FL_ALT))
return 0;
// not handled by the input, use history
int s=history.size();
Fl::focus(this);
if (Fl::event_key()==FL_Up){
--count;
if (count<0)
count=0;
}
else {
++count;
if (count>=s)
count=max(0,s-1);
}
if (countpos2)
giac::swapint(pos1,pos2);
value((v.substr(0,pos1)+history[count]+v.substr(pos2,v.size()-pos2)).c_str());
position(pos1,pos1+history[count].size());
}
set_changed();
return 1;
}
}
if (!completion_tab || event!=FL_KEYBOARD || (Fl::event_text() && Fl::event_text()[0]!=9 && Fl::event_key()!=FL_F+1)){
const char * ch = value();
unsigned l=strlen(ch);
unsigned p=position();
unsigned m=mark();
bool test_backspace=(l && p && p==m && p<=l && ch[p-1]=='\n') || (p!=m);
int res=Fl_Multiline_Input::handle(event);
if (event==FL_KEYBOARD && res ){
match();
redraw();
if ( test_backspace && Fl::event_key()==FL_BackSpace)
resize_nl();
}
return res;
}
string s(value()),ans;
if (position()w(),window()->h()/3,remove,ans)){
window()->show();
cut(-remove-delta);
if (ii==1){
insert((ans+"()").c_str());
position(size()-1);
}
else {
insert(ans.c_str());
position(size());
}
if (parent())
parent_redraw(parent());
}
Fl::focus(this);
handle(FL_FOCUS);
return 1;
}
/* void Multiline_Input_tab::draw(){
int pos=position();
int clip_x,clip_y,clip_w,clip_h;
fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
if (clip_w==0 || clip_h==0)
return;
// if (pos!=mark()){
Fl_Multiline_Input::draw();
return;
// }
} */
// geo_print / geoprint
std::string _pnt2string(const giac::gen & g,const giac::context * contextptr){
unsigned ta=taille(g,100);
if (ta>100)
return "Done";
if (g.is_symb_of_sommet(giac::at_pnt) && !is3d(g)){
giac::gen & f=g._SYMBptr->feuille;
if (f.type==giac::_VECT && !f._VECTptr->empty()){
giac::gen f0=f._VECTptr->front();
if (f0.is_symb_of_sommet(giac::at_legende)){
return g.print(contextptr);
}
if (f0.is_symb_of_sommet(giac::at_curve)){
giac::gen f1=f[0]._SYMBptr->feuille;
if (f1.type==giac::_VECT && !f1._VECTptr->empty() ){
giac::gen f1f=f1._VECTptr->front();
if (f1f.type==giac::_VECT && f1f._VECTptr->size()>=4){
giac::vecteur f1v=*f1f._VECTptr;
return "plotparam("+pnt2string(f1v[0],contextptr)+","+f1v[1].print(contextptr)+"="+f1v[2].print(contextptr)+".."+f1v[3].print(contextptr)+")";
}
}
}
if (f0.is_symb_of_sommet(giac::at_cercle) && f0._SYMBptr->feuille.type==giac::_VECT){
giac::gen centre,rayon;
if (!giac::centre_rayon(f0,centre,rayon,true,0))
return "cercle_error";
if (!complex_mode(contextptr) && (centre.typebegin(),itend=f0._VECTptr->end();
if ( itend-it==2){
switch(f0.subtype){
case giac::_LINE__VECT:
s="droite(";
break;
case giac::_HALFLINE__VECT:
s="demi_droite(";
break;
case giac::_GROUP__VECT:
s="segment(";
break;
}
if (f0.subtype==giac::_LINE__VECT && it->type!=giac::_VECT){ // 2-d line
s += _equation(g,contextptr).print(contextptr) + ")";
return s;
}
}
for (;it!=itend;){
s += "point(";
if (!complex_mode(contextptr) && (it->typetype==giac::_FRAC) )
s += giac::re(*it,contextptr).print(contextptr)+","+giac::im(*it,contextptr).print(contextptr);
else
s+=it->print(contextptr);
s+=")";
++it;
s += it==itend?")":",";
}
return s;
}
if ( (f0.type!=giac::_FRAC && f0.type>=giac::_IDNT) || is3d(g) || complex_mode(contextptr))
return "point("+f0.print(contextptr)+")";
else
return "point("+giac::re(f0,contextptr).print(contextptr)+","+giac::im(f0,contextptr).print(contextptr)+")";
}
}
if (g.type==giac::_VECT && !g._VECTptr->empty() && g._VECTptr->back().is_symb_of_sommet(giac::at_pnt)){
std::string s = "[";
giac::const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;){
s += pnt2string(*it,contextptr);
++it;
s += it==itend?"]":",";
}
return s;
}
return g.print(contextptr);
}
std::string pnt2string(const giac::gen & g,const giac::context * contextptr){
try {
return _pnt2string(g,contextptr);
}
catch (...){
return "conversion error";
}
}
void Gen_Output::value(const giac::gen & _g){
g=_g;
Fl_Multiline_Output::value(pnt2string(g,get_context(this)).c_str());
}
void Gen_Output::value(const char * ch){
giac::context * contextptr=get_context(this);
g=giac::gen(ch,contextptr);
Fl_Multiline_Output::value(ch);
}
giac::gen Gen_Output::value() const {
return g;
}
void Multiline_Input_tab::set_g(const giac::gen & g) {
const giac::context * contextptr = get_context(this);
value(g.print(contextptr).c_str());
redraw();
clear_changed();
_g=g;
}
giac::gen Multiline_Input_tab::g() {
if (!changed())
return _g;
giac::context * contextptr=get_context(this);
_g=giac::gen(value(),contextptr);
clear_changed();
return _g;
}
void Enlargable_Multiline_Output::value(const char * ch){
Fl_Multiline_Output::value(ch);
resize();
}
void Enlargable_Multiline_Output::resize(){
// Count number of \n
const char * ch=Fl_Multiline_Output::value();
int n=strlen(ch);
int h0=labelsize(),res=n?h0+4:1;
int j=0,nc=0,nl=0;
string temp="";
fl_font(textfont(),labelsize());
for (int i=0;iw();
int h=parent()->h();
if (resredraw();
}
Fl_Multiline_Output::resize(x(),y(),nl,res);
}
int Comment_Multiline_Input::handle(int event){
string oldval(value());
int res=in_handle(event);
History_Pack * g=get_history_pack(this);
if (g && value()!=oldval)
g->modified(false);
return res;
}
int Comment_Multiline_Input::in_handle(int event){
if (event==FL_FOCUS){
Xcas_input_focus=this;
autosave_disabled=false;
// Fl::focus(this);
// redraw();
return Fl_Multiline_Input::handle(event);
}
if (event==FL_UNFOCUS){
return Fl_Multiline_Input::handle(event);
}
if (event==FL_KEYBOARD){
redraw();
int key=Fl::event_key();
if ( (key==FL_Enter || key==FL_KP_Enter)
&& Fl::event_shift()){
insert("\n");
increase_size(this,labelsize()+2);
return 1;
}
if (key==FL_BackSpace){
const char * ch = value();
unsigned l=strlen(ch);
unsigned p=position();
unsigned m=mark();
if (l && p && p==m && p<=l && ch[p-1]=='\n'){
increase_size(this,-labelsize()-2);
}
}
History_Pack * hp = get_history_pack(this);
int change_focus=0;
if (hp && ( (key==FL_Up && !line_start(position())) || key==FL_Page_Up))
change_focus=-1;
if (hp && ( (key==FL_Down && line_end(position())==size()) || key==FL_Page_Down || key==FL_Enter))
change_focus=1;
if (key==FL_Enter){
string s=value();
s+=' ';
// search in s for a word with ., check if it's an existing filename or URL
int ss=s.size();
for (int i=0;i='a' && s[i+1]<='z' &&
i && (isalpha(s[i-1]) || (s[i-1]>='0' && s[i-1]<='9'))
)
haspoint=true;
if (s[i]==' ')
break;
}
if (!haspoint)
continue;
string url;
if (i>wordbegin+7 && (s.substr(wordbegin,7)=="http://" || s.substr(wordbegin,7)=="file://")){
url=s.substr(wordbegin,i-wordbegin);
}
else {
if (s[wordbegin]=='@'){
url=s.substr(wordbegin+1,i-wordbegin-1);
}
}
if (url.empty())
continue;
if (giac::is_file_available(url.c_str())){
if (url[0]!='/')
url=*giac::_pwd(0,0)._STRNGptr+"/"+url;
}
else {
if (url.size()<7 || (url.substr(0,7)!="http://" && url.substr(0,7)!="file://"))
url="http://"+url;
}
giac::system_browser_command(url);
// break;
}
}
if (change_focus && hp){
hp->_sel_begin=-1;
int pos=hp->set_sel_begin(this);
if (pos+change_focus>=0)
hp->focus(pos+change_focus,true);
return 1;
}
}
return Fl_Multiline_Input::handle(event);
}
#ifndef NO_NAMESPACE_XCAS
} // namespace xcas
#endif // ndef NO_NAMESPACE_XCAS
#endif // HAVE_LIBFLTK