1 // -*- compile-command: "g++ -DHAVE_CONFIG_H -I. -I.. -g -c Tableur.cc -Wall" -*-
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #ifndef IN_GIAC
6 #include <giac/first.h>
7 #else
8 #include "first.h"
9 #endif
10 /*
11  *  Copyright (C) 2002,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #ifdef HAVE_LIBFLTK
28 #include "Tableur.h"
29 #include "Xcas1.h"
30 #include "Print.h"
31 #ifndef IN_GIAC
32 #include <giac/vecteur.h>
33 #else
34 #include "vecteur.h"
35 #endif
36 #ifndef IN_GIAC
37 #include <giac/identificateur.h>
38 #include <giac/usual.h>
39 #include <giac/prog.h>
40 #include <giac/misc.h>
41 #include <giac/global.h>
42 #else
43 #include "identificateur.h"
44 #include "usual.h"
45 #include "prog.h"
46 #include "misc.h"
47 #include "global.h"
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 
53 #include <FL/Fl_Text_Editor.H>
54 #include <FL/Fl_Value_Input.H>
55 #include <FL/Fl_Return_Button.H>
56 #include <FL/Fl_Check_Button.H>
57 #include <sys/stat.h>
58 #include <cerrno>
59 using namespace std;
60 using namespace giac;
61 
62 #ifndef NO_NAMESPACE_XCAS
63 namespace xcas {
64 #endif // ndef NO_NAMESPACE_XCAS
65 
66   objet_bidon mon_objet_bidon_tableur;
67 
68 #ifdef IPAQ
69   int Flv_Table_Gen::def_rows=10,Flv_Table_Gen::def_cols=4;
70 #else
71   int Flv_Table_Gen::def_rows=40,Flv_Table_Gen::def_cols=10;
72 #endif
73 
fillsheet(bool is_spreadsheet)74   vecteur fillsheet(bool is_spreadsheet){
75     vecteur res;
76     if (is_spreadsheet)
77       res=vecteur(3,string2gen(string(""),false));
78     else
79       res=vecteur(3,zero);
80     res[2]=plus_two;
81     return res;
82   }
83 
do_find_table_brother(Fl_Widget * widget)84   Flv_Table_Gen * do_find_table_brother(Fl_Widget * widget){
85     if (!widget)
86       return 0;
87     Fl_Group * gr = widget->parent();
88     if (!gr)
89       return 0;
90     Flv_Table_Gen * spread_ptr=0;
91     int n=gr->children();
92     for (int i=0;i<n;++i){
93       if ( (spread_ptr= dynamic_cast<Flv_Table_Gen *>(gr->child(i))) )
94 	break;
95     }
96     if (!spread_ptr)
97       return do_find_table_brother(gr);
98     return spread_ptr;
99   }
100 
find_table_brother(Fl_Widget * widget)101   Flv_Table_Gen * find_table_brother(Fl_Widget * widget){
102     Flv_Table_Gen * ptr = do_find_table_brother(widget);
103     if (!ptr)
104       ptr=do_find_table_brother(Fl::focus());
105     if (!ptr)
106       fl_alert("%s",gettext("No spreadsheet found. Please click in or add one"));
107     return ptr;
108   }
109 
cb_Tableur_Recompute(Fl_Menu_ * m,void *)110    void cb_Tableur_Recompute(Fl_Menu_* m , void*) {
111     Flv_Table_Gen * spread_ptr=find_table_brother(m);
112     if (spread_ptr){
113       spread_ptr->spread_eval_interrupt();
114       spread_ptr->redraw();
115     }
116   }
117 
changed()118   void Flv_Table_Gen::changed(){
119     changed_=true;
120     backup();
121   }
122 
config()123   void Flv_Table_Gen::config(){
124     static Fl_Window * w = 0;
125     static Fl_Input * varname=0,*input_init=0; // sheet variable name
126     static Fl_Check_Button* evaltype=0,*moveright=0,*mat2cell=0,* issheet=0,*horiz=0,*viewgr=0;
127     static Fl_Value_Input * nrow=0,*ncol=0,*max_hist=0;
128     static Fl_Return_Button * button0 = 0 ;
129     static Fl_Button * button1 =0;
130     if (!w){
131       int nlignes=8;
132 #ifdef IPAQ
133       int dx=240,dy=300;
134 #else
135       int dx=20*labelsize(), dy=14*labelsize();
136 #endif
137       Fl_Group::current(0);
138       w=new Fl_Window(dx,dy);
139       varname=new Fl_Input(dx/2,2,dx/2-4,dy/nlignes-4,gettext("Variable"));
140       varname->tooltip(gettext("Save the spreadsheet as a matrix in this variable"));
141       nrow = new Fl_Value_Input(dx/4,2+dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Rows"));
142       nrow->minimum(1);
143       nrow->maximum(1000);
144       nrow->step(1);
145       ncol = new Fl_Value_Input(3*dx/4,2+dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Cols"));
146       ncol->minimum(1);
147       ncol->maximum(1000);
148       ncol->step(1);
149       evaltype = new Fl_Check_Button(2,2+2*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Eval"));
150       evaltype->tooltip(gettext("Reeval spreadsheet automatically"));
151       // evaltype->callback((Fl_Callback *) cb_Tableur_Recompute);
152       moveright = new Fl_Check_Button(2+dx/2,2+2*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Move right"));
153       moveright->tooltip(gettext("Move right or down after Enter"));
154       mat2cell = new Fl_Check_Button(2,2+3*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Distribute"));
155       mat2cell->tooltip(gettext("Matrix input is distributed or kept inside a cell"));
156       issheet = new Fl_Check_Button(2+dx/2,2+3*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Spreadsheet"));
157       issheet->tooltip(gettext("Matrix or spreadsheet"));
158       horiz = new Fl_Check_Button(2,2+4*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Landscape"));
159       horiz->tooltip(gettext("Split sheet/graph horizontally or vertically"));
160       viewgr = new Fl_Check_Button(2+dx/2,2+4*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Graph"));
161       viewgr->tooltip(gettext("Show or hide graph connected to this sheet"));
162       max_hist = new Fl_Value_Input(3*dx/4,2+5*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Undo history"));
163       input_init = new Fl_Input(3*dx/4,2+6*dy/nlignes,dx/4-2,dy/nlignes-4,gettext("Init sheet"));
164       button0 = new Fl_Return_Button(2,2+7*dy/nlignes,dx/2-4,dy/nlignes-4);
165       button0->shortcut(0xff0d);
166       button0->label(gettext("OK"));
167       button1 = new Fl_Button(dx/2+2,2+7*dy/nlignes,dx/2-4,dy/nlignes-4);
168       button1->shortcut(0xff1b);
169       button1->label(gettext("Cancel"));
170       w->end();
171       change_group_fontsize(w,labelsize());
172       w->resizable(w);
173       w->label(gettext("Sheet configuration"));
174     }
175     Tableur_Group * gr = dynamic_cast<Tableur_Group *>(parent());
176     contextptr = get_context(gr);
177     varname->value(name.print(contextptr).c_str());
178     nrow->value(rows());
179     ncol->value(cols());
180     max_hist->value(max_history);
181     issheet->value(is_spreadsheet);
182     mat2cell->value(matrix_fill_cells);
183     moveright->value(move_right);
184     evaltype->value(spreadsheet_recompute);
185     input_init->value(init.print(contextptr).c_str());
186     if (gr){
187       viewgr->value(gr->disposition/2);
188       horiz->value(!(gr->disposition % 2));
189     }
190     int r=-1;
191     w->set_modal();
192     w->show();
193     autosave_disabled=true;
194     w->hotspot(w);
195     Fl::focus(varname);
196     for (;;) {
197       Fl_Widget *o = Fl::readqueue();
198       if (!o) Fl::wait();
199       else {
200 	if (o == button0) {r = 0; break;}
201 	if (o == button1) {r = 1; break;}
202 	if (o == w) { r=1; break; }
203       }
204     }
205     autosave_disabled=false;
206     w->hide();
207     if (!r){
208       max_history=max(int(max_hist->value()),2);
209       if ( nrow->value()>=1 && ncol->value()>=1 && (nrow->value()!=rows() || ncol->value()!= cols()) ){
210 	changed();
211 	resizesheet(int(nrow->value()),int(ncol->value()));
212 	if ((7+nrow->value())*(labelsize()+1)<h()){
213 	  increase_size(this,(7+nrow->value())*(labelsize()+1)-h());
214 	}
215       }
216       is_spreadsheet=issheet->value();
217       matrix_fill_cells=mat2cell->value();
218       move_right=moveright->value();
219       is_spreadsheet=issheet->value();
220       init=gen(input_init->value(),contextptr);
221       if (init.type==_SYMB)
222 	protecteval(init,eval_level(contextptr),contextptr);
223       if (!spreadsheet_recompute && evaltype->value()){
224 	spreadsheet_recompute=evaltype->value();
225 	spread_eval_interrupt();
226       }
227       else
228 	spreadsheet_recompute=evaltype->value();
229       gen tmp(varname->value(),contextptr);
230       if (tmp.type==_IDNT && !is_undef(tmp)){
231 	name=tmp;
232 	if (filename)
233 	  delete filename;
234 	filename = new string(tmp.print(contextptr)+".tab");
235 	if (filename){
236 	  prefix_filename="Save "+ remove_path(* filename);
237 	  if (Tableur_Group * gr=dynamic_cast<Tableur_Group *>(parent())){
238 	    gr->fname->label(prefix_filename.c_str());
239 	    gr->fname->show();
240 	  }
241 	}
242 	sto(extractmatricefromsheet(m),name,contextptr);
243       }
244       if (gr){
245 	if (!viewgr->value() && (gr->disposition & 0x2))
246 	  gr->save_dparam();
247 	gr->disposition=2*viewgr->value()+!horiz->value();
248 	gr->resize2();
249       }
250       update_status();
251     }
252     if (gr) Fl::focus(gr->table);
253   }
254 
spread_erase(int nrows,int ncols)255   void Flv_Table_Gen::spread_erase(int nrows,int ncols){
256     changed();
257     if ( (nrows>=rows()) || (ncols>=cols()) )
258       return;
259     contextptr=get_context(this);
260     m=matrice_erase(m,row(),col(),nrows,ncols,contextptr);
261     rows(rows()-nrows);
262     cols(cols()-ncols);
263     row(min(rows()-1,row()));
264     col(min(cols()-1,col()));
265     update_status();
266     update_name();
267   }
268 
269 
blank(int row_min,int r,int col_min,int c)270   void Flv_Table_Gen::blank(int row_min,int r,int col_min,int c){
271     changed();
272     vecteur fill(fillsheet(is_spreadsheet));
273     if (c<col_min)
274       swap(c,col_min);
275     if (r<row_min)
276       swap(r,row_min);
277     ++r;
278     r=min(rows(),r);
279     ++c;
280     c=min(cols(),c);
281     if ( (c==col_min) || (r==row_min) )
282       return;
283     selected.clear();
284     selected.reserve(r-row_min);
285     for (int i=row_min;i<r;++i){
286       vecteur & v=*m[i]._VECTptr;
287       vecteur tmp;
288       tmp.reserve(c-col_min);
289       for (int j=col_min;j<c;++j){
290 	tmp.push_back(v[j]);
291 	v[j]=freecopy(fill);
292       }
293       selected.push_back(tmp);
294     }
295     redraw();
296     update_name();
297   }
298 
blank()299   void Flv_Table_Gen::blank(){
300     changed();
301     int row_min=select_start_row(),r=row();
302     int col_min=select_start_col(),c=col();
303     blank(row_min,r,col_min,c);
304   }
305 
spread_insert(int nrows,int ncols)306   void Flv_Table_Gen::spread_insert(int nrows,int ncols){
307     changed();
308     vecteur fill(fillsheet(is_spreadsheet));
309     contextptr=get_context(this);
310     m=matrice_insert(m,row(),col(),nrows,ncols,fill,contextptr);
311     rows(rows()+nrows);
312     cols(cols()+ncols);
313     update_status();
314     redraw();
315     update_name();
316   }
317 
addrowatend()318   void Flv_Table_Gen::addrowatend(){
319     changed();
320     vecteur fill(fillsheet(is_spreadsheet));
321     int C=cols();
322     vecteur addrow(C);
323     for (int j=0;j<C;++j)
324       addrow[j]=freecopy(fill);
325     m.push_back(addrow);
326     rows(rows()+1);
327     update_status();
328     redraw();
329     update_name();
330   }
331 
addcolatend()332   void Flv_Table_Gen::addcolatend(){
333     changed();
334     vecteur fill(fillsheet(is_spreadsheet));
335     int R=rows();
336     for (int i=0;i<R;++i){
337       m[i]._VECTptr->push_back(freecopy(fill));
338     }
339     cols(cols()+1);
340     update_status();
341     redraw();
342     update_name();
343   }
344 
resizesheet(int nr,int nc)345   void Flv_Table_Gen::resizesheet(int nr,int nc){
346     changed();
347     int cur_r=rows();
348     vecteur fill(fillsheet(is_spreadsheet));
349     if (nr<cur_r) // erase rows
350       m=vecteur(m.begin(),m.begin()+nr);
351     else {
352       for (;cur_r<nr;++cur_r){
353 	vecteur tmp;
354 	for (int j=0;j<nc;++j)
355 	  tmp.push_back(freecopy(fill));
356 	m.push_back(tmp);
357       }
358     }
359     for (int i=0;i<nr;++i){
360       vecteur & v=*m[i]._VECTptr;
361       int cur_c=v.size();
362       if (nc<cur_c){
363 	m[i]=vecteur(v.begin(),v.begin()+nc);
364       }
365       else {
366 	for (;cur_c<nc;++cur_c)
367 	  v.push_back(freecopy(fill));
368       }
369     }
370     rows(nr);
371     cols(nc);
372     row(0);
373     col(0);
374     spread_eval_interrupt();
375     update_status();
376     redraw();
377     update_name();
378   }
379 
copy(int clipboard)380   void Flv_Table_Gen::copy(int clipboard){
381     contextptr = get_context(this);
382     int row_min=select_start_row(),r=row();
383     int col_min=select_start_col(),c=col();
384     selected.clear();
385     if (c<col_min)
386       swap(c,col_min);
387     if (r<row_min)
388       swap(r,row_min);
389     ++r;
390     ++c;
391     if ( (c==col_min) || (r==row_min) )
392       return;
393     selected.reserve(r-row_min);
394     for (int i=row_min;i<r;++i){
395       vecteur tmp;
396       tmp.reserve(c-col_min);
397       for (int j=col_min;j<c;++j){
398 	tmp.push_back(m[i][j]);
399       }
400       selected.push_back(tmp);
401     }
402     gen g(extractmatricefromsheet(selected));
403     static string s;
404     s=g.print(contextptr);
405     // Fl::selection(*this,s.c_str(),s.size());
406     Fl::copy(s.c_str(),s.size(),clipboard);
407     update_name();
408   }
409 
copy_right()410   void Flv_Table_Gen::copy_right(){
411     changed();
412     int R=row(),C=col();
413     int c=cols(),r=rows();
414     int R0=select_start_row();
415     if (R0<0 || R0>=r)
416       R0=R;
417     if (R0<R)
418       giac::swapint(R0,R);
419     for (;R<=R0;++R){
420       vecteur & v=*m[R]._VECTptr;
421       gen g=v[C];
422       for (int i=C+1;i<c;++i){
423 	v[i]=freecopy(g);
424       }
425     }
426     spread_eval_interrupt();
427     redraw();
428   }
429 
copy_down()430   void Flv_Table_Gen::copy_down(){
431     changed();
432     int R=row(),C=col();
433     int r=rows(),c=cols();
434     int C0=select_start_col();
435     if (C0<0 || C0>=c)
436       C0=C;
437     if (C0<C)
438       giac::swapint(C0,C);
439     for (;C<=C0;++C){
440       gen g=m[R][C];
441       for (int i=R+1;i<r;++i){
442 	vecteur & v=*m[i]._VECTptr;
443 	v[C]=freecopy(g);
444       }
445     }
446     spread_eval_interrupt();
447     redraw();
448   }
449 
copy_first_in_selection()450   void Flv_Table_Gen::copy_first_in_selection(){
451     changed();
452     int R=row(),C=col();
453     int r=select_start_row(),c=select_start_col();
454     if (r==R && c==C)
455       return;
456     gen g=m[r][c];
457     if (r<R)
458       giac::swapint(r,R);
459     if (c<C)
460       giac::swapint(c,C);
461     R=max(R,0); C=max(C,0); r=min(r,rows()-1); c=min(c,cols()-1);
462     for (int i=R;i<=r;++i){
463       vecteur & v=*m[i]._VECTptr;
464       for (int j=C;j<=c;++j)
465 	v[j]=freecopy(g);
466     }
467     spread_eval_interrupt();
468     update_input();
469     redraw();
470   }
471 
paste(const matrice & m_orig,bool reeval)472   void Flv_Table_Gen::paste(const matrice & m_orig,bool reeval){
473     changed();
474     contextptr=get_context(this);
475     matrice m_copy(makefreematrice(m_orig));
476     makespreadsheetmatrice(m_copy,contextptr);
477     int nr,nc;
478     mdims(m_copy,nr,nc);
479     int r=row(),c=col();
480     if (r+nr>rows()||c+nc>cols())
481       resizesheet(max(r+nr,rows()),max(c+nc,cols()));
482     int R=min(r+nr,rows()),C=min(c+nc,cols());
483     for (int i=r;i<R;++i){
484       vecteur & v=*m[i]._VECTptr;
485       for (int j=c;j<C;++j){
486 	v[j]=m_copy[i-r][j-c];
487       }
488     }
489     if (reeval)
490       spread_eval_interrupt();
491     update_input();
492     redraw();
493   }
494 
erase_row_col(int i)495   void Flv_Table_Gen::erase_row_col(int i){
496     int R=row(),C=col();
497     // erase rows push_row -> R && push_col -> C
498     if (i==2)
499       i=fl_choice(gettext("Remove what?"),gettext("Rows"),gettext("Cols"),gettext("Cancel"));
500     int r1=min(push_row,R),r2=absint(push_row-R)+1,c1=min(push_col,C),c2=absint(push_col-C)+1;
501     if (i==0){
502       row(r1);
503       push_row=r1;
504       spread_erase(r2,0);
505     }
506     if (i==1){
507       col(c1);
508       push_col=c1;
509       spread_erase(0,c2);
510     }
511   }
512 
update_goto()513   void Flv_Table_Gen::update_goto(){
514     contextptr = get_context(this);
515     if (_goto){
516       printcell_current_row(contextptr)=row();
517       printcell_current_col(contextptr)=col();
518       string s_s=printcell(makevecteur(makevecteur(0),makevecteur(0)),contextptr);
519       _goto->value(s_s.c_str());
520     }
521   }
522 
update_input()523   void Flv_Table_Gen::update_input(){
524     contextptr = get_context(this);
525     int R=row();
526     int C=col();
527     edit_row=R;
528     edit_col=C;
529     if (input && R<rows() && C<cols()){
530       gen tmp=m[R][col()];
531       if (tmp.type==_VECT && tmp._VECTptr->size()==3)
532 	tmp=tmp._VECTptr->front();
533       input->value(tmp.print(contextptr).c_str());
534       input->position(0,input->value().size());
535       // input->position(0,strlen(input->value()));
536     }
537   }
538 
enter_move()539   void Flv_Table_Gen::enter_move(){
540     int R=row(),C=col();
541     if (!move_right){
542       if (R<rows()-1)
543 	row(R+1);
544       else {
545 	row(0);
546 	if (C<cols()-1)
547 	  col(C+1);
548 	else
549 	  col(0);
550       }
551     }
552     else {
553       if (C<cols()-1)
554 	col(C+1);
555       else {
556 	col(0);
557 	if (R<rows()-1)
558 	  row(R+1);
559 	else
560 	  row(0);
561       }
562     }
563     select_start_row(row());
564     select_start_col(col());
565     update_goto();
566     redraw();
567     update_input();
568   }
569 
570 
handle(int event)571   int Flv_Table_Gen::handle(int event){
572     if (event==FL_MOUSEWHEEL){
573       if (!Fl::event_inside(this))
574 	return 0;
575     }
576     contextptr = get_context(this);
577     static string s;
578     if (Fl::event_button()== FL_RIGHT_MOUSE)
579       return 0;
580     last_event=event;
581     if (event==FL_KEYBOARD){
582       Xcas_input_focus=this;
583       // int mode=Fl::event_state(FL_CTRL);
584       if (Fl::event_key()==FL_Escape){
585 	editing=false;
586 	// cerr << "Mtrw edit leave"<<'\n';
587       }
588       if (Fl::event_key()==FL_Delete){
589 	erase_row_col(2);
590 	return 1;
591       }
592       if (Fl::event_key()==FL_Enter || Fl::event_key()==FL_KP_Enter){
593 	enter_move();
594 	return 1;
595       }
596       switch (Fl::event_key()){
597       case FL_Control_R: case FL_Control_L: case FL_Alt_L: case FL_Alt_R:
598 	return 0;
599       }
600       char ch=Fl::event_text()?Fl::event_text()[0]:0;
601       if (ch==3){
602 	if (selected.empty() && row()>=0 && row()<rows() && col()>=0 && col()<cols())
603 	  selected_1=vecteur(1,vecteur(1,m[row()][col()]));
604 	else
605 	  selected_1=selected;
606 	copy(1);
607 	return 1;
608       }
609       if (ch==22){
610 	if (selected_1.empty()){
611 	  Fl::paste(*this,1);
612 	}
613 	else
614 	  paste(selected_1);
615 	return 1;
616       }
617       if (ch==25){
618 	restore(1);
619 	return 1;
620       }
621       if (ch==26){
622 	restore(-1);
623 	return 1;
624       }
625       if (ch==4 || ch==18)
626 	return 0;
627     }
628     int res=Flv_Table::handle(event);
629     if (!editing){
630       edit_row=row();
631       edit_col=col();
632     }
633     bool shift=Fl::event_state(FL_SHIFT);
634     if (event==FL_FOCUS){
635       Fl::focus(this);
636       return 1;
637     }
638     if (event==FL_PUSH && Fl::focus()!=this)
639       Fl::focus(this);
640     if (event==FL_RELEASE){
641       set_cursor(this,FL_CURSOR_ARROW);
642       if (editing)
643 	click_fill=false;
644       if (click_fill){ // fill area
645 	copy_first_in_selection();
646 	click_fill=false;
647 	return 1;
648       }
649     }
650     if (event==FL_RELEASE && Fl::event_button()== FL_MIDDLE_MOUSE ){
651       Fl::paste(*this);
652       return 1;
653     }
654     if (event==FL_PASTE){
655       if (selected.empty()){
656 	Fl::focus(input);
657 	input->handle(FL_PASTE);
658 	input->do_callback();
659       }
660       else
661 	paste(selected);
662       return 1;
663     }
664     if ( event==FL_UNFOCUS || event==FL_HIDE || event==FL_SHOW ){
665       /*
666       if (event==FL_UNFOCUS){
667 	selected.clear();
668 	selected_1.clear();
669       }
670       */
671       return res;
672     }
673     if (res){
674       int R=row(),C=col();
675       printcell_current_row(contextptr)=R;
676       printcell_current_col(contextptr)=C;
677       s=printcell(makevecteur(makevecteur(0),makevecteur(0)),contextptr);
678       bool head=header_event==FLVE_ROW_HEADER_CLICKED || header_event==FLVE_COL_HEADER_CLICKED ||header_event==FLVE_ROW_FOOTER_CLICKED || header_event==FLVE_COL_FOOTER_CLICKED;
679       if (head){
680 	if (event==FL_PUSH){
681 	  if (header_event==FLVE_ROW_HEADER_CLICKED){
682 	    push_col=col();
683 	    push_row=rows()-1;
684 	  }
685 	  if (header_event==FLVE_ROW_FOOTER_CLICKED){
686 	    push_col=col();
687 	    push_row=0;
688 	  }
689 	  if (header_event==FLVE_COL_HEADER_CLICKED){
690 	    push_col=cols()-1;
691 	    push_row=row();
692 	  }
693 	  if (header_event==FLVE_COL_FOOTER_CLICKED){
694 	    push_col=0;
695 	    push_row=row();
696 	  }
697 	}
698 	s=printcell(makevecteur(makevecteur(push_row-R),makevecteur(push_col-C)),contextptr)+":"+s;
699       }
700       else { // else head
701 	if (event==FL_PUSH){
702 	  if (shift){
703 	    editing=false;
704 	    select_start_row(push_row);
705 	    select_start_col(push_col);
706 	  }
707 	  else {
708 	    push_row=R;
709 	    push_col=C;
710 	  }
711 	  if (!editing){
712 	    edit_row=R;
713 	    edit_col=C;
714 	  }
715 	}
716 	else {
717 	  if (push_row!=R || push_col!=C) {
718 	    if (editing)
719 	      s=printcell(makevecteur(makevecteur(push_row-R),makevecteur(push_col-C)),contextptr)+":"+s;
720 	    else
721 	      if (event==FL_DRAG || event==FL_RELEASE ){
722 		s=printcell(makevecteur(makevecteur(push_row-R),makevecteur(push_col-C)),contextptr)+":"+s;
723 	      }
724 	  }
725 	}
726       } // end else header_event
727       if (event!=FL_ENTER && event!=FL_LEAVE && event!=FL_MOVE && _goto)
728 	_goto->value(s.c_str());
729       if (editing && (header_event || (event==FL_PUSH || event ==FL_DRAG || event == FL_RELEASE) ) ){
730 	header_event = 0;
731 	if (event==FL_PUSH || event ==FL_DRAG || event == FL_RELEASE)
732 	  input->insert_replace(s.c_str(),true);
733 	if (event==FL_RELEASE){
734 	  row(edit_row); col(edit_col); select_start_row(edit_row); select_start_col(edit_col);
735 	  Fl::focus(input);
736 	  // int s=strlen(input->value());
737 	  input->position(input->mark(),input->mark());
738 	  if (_goto){
739 	    _goto->value(printcell(makevecteur(makevecteur(edit_row-R),makevecteur(edit_col-C)),contextptr).c_str());
740 	  }
741 	  return 1;
742 	}
743 	if (editing)
744 	  return 1;
745       }
746       if (head || (event==FL_RELEASE && (push_row!=R || push_col!=C)) ){
747 	header_event = 0;
748 	copy();
749 	if (Xcas_help_output){
750 	  gen g=extractmatricefromsheet(selected);
751 	  static string s1;
752 	  s1=g.print(contextptr);
753 	  Xcas_help_output->value(s1.c_str());
754 	}
755 	return 1;
756       }
757       if ( !editing && (C>=0) && (R>=0) && (event!=FL_MOVE) && (event!=FL_ENTER) && (event!=FL_LEAVE) ){
758 	if ( (m[R][C].type==_VECT) && (m[R][C]._VECTptr->size()==3) ){
759 	  int save_r=printcell_current_row(contextptr),save_c=printcell_current_col(contextptr);
760 	  printcell_current_row(contextptr)=R,printcell_current_col(contextptr)=C;
761 	  s=m[R][C][0].print(contextptr);
762 	  printcell_current_row(contextptr)=save_r;printcell_current_col(contextptr)=save_c;
763 	}
764 	else
765 	  s=m[R][C].print(contextptr);
766 	input->value(s.c_str());
767 	input->position(0,s.size());
768       }
769     }
770     if (!res && !shift && event==FL_KEYBOARD && !editing){
771       editing=true;
772       edit_row=row(); edit_col=col();
773       Fl::focus(input);
774       int r=Fl::handle(FL_KEYBOARD,window());
775       return 1;
776     }
777     return res;
778   }
779 
780 #ifdef HAVE_LIBPTHREAD
in_thread_spread_eval(void * arg)781   void * in_thread_spread_eval(void * arg){
782     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
783     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
784     vecteur *v = (vecteur *) arg;
785     context * contextptr=(context *) (*v)[2]._POINTER_val;
786     matrice * mptr = (matrice *) (*v)[0]._POINTER_val;
787     giac::spread_eval(*mptr,contextptr);
788     thread_eval_status(0,contextptr);
789     pthread_exit(0);
790   }
791 
thread_spread_eval(matrice & m,GIAC_CONTEXT)792   void thread_spread_eval(matrice &m,GIAC_CONTEXT){
793     if (is_context_busy(contextptr))
794       return;
795     bool old_io_graph=io_graph(contextptr);
796     io_graph(false,contextptr);
797     pthread_t spread_eval_thread;
798     giac::vecteur v(3);
799     v[0]=gen((void *)&m,3);
800     v[2]=gen((void *) contextptr,3);
801     thread_eval_status(1,contextptr);
802     pthread_mutex_lock(mutexptr(contextptr));
803     int cres=pthread_create (&spread_eval_thread, (pthread_attr_t *) NULL, in_thread_spread_eval,(void *)&v);
804     if (!cres){
805       Fl::remove_idle(xcas::Xcas_idle_function,0);
806       for (;;){
807 	int eval_status=thread_eval_status(contextptr);
808 	if (!eval_status)
809 	  break;
810 	Fl::wait(0.0001);
811 	if (kill_thread(contextptr)){
812 	  kill_thread(false,contextptr);
813 	  try {
814 	    pthread_cancel(spread_eval_thread) ;
815 	  } catch (std::runtime_error & err){
816 	  }
817 	  pthread_mutex_unlock(mutexptr(contextptr));
818 	  Fl::add_idle(xcas::Xcas_idle_function,0);
819 	  fl_message("%s",gettext("computation aborted"));
820 	  io_graph(old_io_graph,contextptr);
821 	  return ;
822 	}
823 	Xcas_idle_function((void *)contextptr);
824       }
825       void * ptr;
826       pthread_join(spread_eval_thread,&ptr);
827       // Restore pointers
828       pthread_mutex_unlock(mutexptr(contextptr));
829       Fl::add_idle(xcas::Xcas_idle_function,0);
830       return ;
831     }
832     pthread_mutex_unlock(mutexptr(contextptr));
833     spread_eval(m,contextptr);
834     io_graph(old_io_graph,contextptr);
835   }
836 
837 #else
838 
thread_spread_eval(matrice & m,GIAC_CONTEXT)839   void thread_spread_eval(matrice &m,GIAC_CONTEXT){
840     spread_eval(m,contextptr);
841   }
842 #endif
843 
set_matrix(const matrice & mym,bool interruptible,bool reeval)844   void Flv_Table_Gen::set_matrix(const matrice & mym,bool interruptible,bool reeval){
845     changed();
846     m=makefreematrice(mym);
847     cols(mcols(m));
848     rows(m.size());
849     contextptr=get_context(this);
850     makespreadsheetmatrice(m,contextptr);
851     if (is_spreadsheet && reeval) {
852       if (interruptible)
853 	spread_eval_interrupt();
854       else {
855 	evaled_table(contextptr)=(void *) this;
856 	spread_eval(m,contextptr);
857       }
858     }
859     /*
860     if (is_spreadsheet)
861       spread_eval_interrupt();
862     */
863     is_spreadsheet=false;
864     if ( !mym.empty() && (!mym.front()._VECTptr->empty()) )
865       is_spreadsheet=(mym[0][0].type==_VECT);
866     move_on_enter(FLV_MOVE_ON_ENTER_COL_ROW);
867     col(0);
868     row(0);
869     select_start_row(0);
870     select_start_col(0);
871     redraw();
872   }
873 
update_status()874   void Flv_Table_Gen::update_status() {
875     contextptr = get_context(this);
876     redraw();
877     status_string = "Sheet config: ";
878     status_string += changed_?"* ":"- ";
879     status_string += is_spreadsheet?"Spreadsheet ":"Matrix ";
880     status_string += (name.type==_IDNT?name.print(contextptr):string("<>"))+" ";
881     if (filename){
882       if (Fl_Group * g=parent()){
883 	int n=g->children();
884 	for (int i=0;i<n;++i){
885 	  if (Fl_Output * o=dynamic_cast<Fl_Output *>(g->child(i))){
886 	    o->value(filename->c_str());
887 	  }
888 	}
889       }
890     }
891     status_string += "R" +print_INT_(rows())+"C"+print_INT_(cols())+" ";
892     status_string += spreadsheet_recompute?"auto ":"manual ";
893     switch(matrix_symmetry){
894     case 1:
895       status_string += "Antihermitian ";
896       break;
897     case 2:
898       status_string += "Hermitian ";
899       break;
900     case 3:
901       status_string += "Antisymmetric ";
902       break;
903     case 4:
904       status_string += "Symmetric ";
905     }
906     status_string += move_right?"right ":"down ";
907     status_string += matrix_fill_cells?"fill":"cell";
908     label(status_string.c_str());
909   }
910 
set_matrix(const gen & g,bool interruptible,bool reeval)911   void Flv_Table_Gen::set_matrix(const gen & g,bool interruptible,bool reeval){
912     changed();
913     if (!ckmatrix(g,true))
914       settypeerr();
915     set_matrix(*g._VECTptr,interruptible,reeval);
916   }
917 
backup()918   void Flv_Table_Gen::backup(){
919     int vs=m_history.size();
920     if (cur_history==vs){
921       if (vs==max_history)
922 	m_history.erase(m_history.begin());
923       else
924 	++cur_history;
925       m_history.push_back(makefreematrice(m));
926     }
927     else {
928       m_history[cur_history]=makefreematrice(m);
929       ++cur_history;
930     }
931   }
932 
restore(int delta)933   void Flv_Table_Gen::restore(int delta){
934     int vs=m_history.size();
935     if (delta==-1 && cur_history==vs){
936       backup();
937       --delta;
938     }
939     cur_history += delta;
940     if (cur_history<0)
941       cur_history=0;
942     if (vs && cur_history<vs){
943       m=*m_history[cur_history]._VECTptr;
944       changed_=true;
945       int r,c;
946       mdims(m,r,c);
947       rows(r);
948       cols(c);
949       redraw();
950     }
951     else
952       cur_history=vs;
953   }
954 
~Flv_Table_Gen()955   Flv_Table_Gen::~Flv_Table_Gen(){
956     if (Xcas_input_focus==this) Xcas_input_focus=0;
957     contextptr=get_context(this);
958     if (evaled_table(contextptr)==this)
959       evaled_table(contextptr)=0;
960     if (win2){
961       win2->hide();
962       delete win2;
963     }
964     if (win3){
965       win3->hide();
966       delete win3;
967     }
968   }
969 
Flv_Table_Gen(int X,int Y,int W,int H,const matrice & mym,const char * l)970   Flv_Table_Gen::Flv_Table_Gen( int X, int Y, int W, int H ,const matrice & mym, const char *l) : Flv_Table(X,Y,W,H,l),max_history(4),cur_history(0),matrix_fill_cells(true),move_right(false),matrix_symmetry(0),spreadsheet_recompute(true),push_row(0),push_col(0),contextptr(0),editing(false),computing(false),filename(0),max_printsize(1024) {
971     if (!ckmatrix(mym))
972       settypeerr();
973     set_matrix(mym,false);
974     changed_=false;
975     graph3d=0; graph2d=0; graph=0; _goto=0; input=0;
976     name=0; init=0;
977     finish_flv_table_gen();
978   }
979 
Flv_Table_Gen(int X,int Y,int W,int H,const gen & g,const char * l)980   Flv_Table_Gen::Flv_Table_Gen( int X, int Y, int W, int H ,const gen &g, const char *l) :   Flv_Table(X,Y,W,H,l),matrix_fill_cells(true),move_right(false),matrix_symmetry(0),spreadsheet_recompute(true),push_row(0),push_col(0),contextptr(0),editing(false),computing(false),filename(0),max_printsize(1024) {
981     set_matrix(g,false);
982     changed_=false;
983     graph2d=0; graph3d=0; graph=0; _goto=0; input=0;
984     name=0; init=0;
985     finish_flv_table_gen();
986   }
987 
parse_interval(const char * ch)988   gen parse_interval(const char * ch){
989     gen g=undef;
990     string s;
991     int l=strlen(ch);
992     for (int i=0;i<l;++i,++ch){
993       if (*ch==':')
994 	s += "..";
995       else
996 	s+=*ch;
997     }
998     try {
999       g=gen(s,context0); // ok
1000     }
1001     catch (std::runtime_error & e){
1002       if (Xcas_help_output)
1003 	Xcas_help_output->value(e.what());
1004     }
1005     return g;
1006   }
1007 
next_cell(const string & s,Flv_Table_Gen * ptr)1008   string next_cell(const string & s,Flv_Table_Gen * ptr){
1009     if (!ptr) return "";
1010     const giac::context * contextptr = get_context(ptr);
1011     int maxr=ptr->rows(),maxc=ptr->cols();
1012     gen g=parse_interval(s.c_str());
1013     if (g.is_symb_of_sommet(at_interval)){
1014       gen & f=g._SYMBptr->feuille;
1015       if (f.type!=_VECT || f._VECTptr->size()!=2)
1016 	return "";
1017       int r1,r2,c1,c2;
1018       if (!iscell(f._VECTptr->front(),c1,r1,contextptr) || !iscell(f._VECTptr->back(),c2,r2,contextptr))
1019 	return "";
1020       if (r1>r2)
1021 	giac::swapint(r1,r2);
1022       if (c1>c2)
1023 	giac::swapint(c1,c2);
1024       // search for an empty cell
1025       for (int j=c2+1;j<maxc;++j){
1026 	for (int i=0;i<maxr;++i){
1027 	  gen tmp=ptr->m[i][j][0];
1028 	  if (is_zero(tmp,contextptr)|| (tmp.type==_STRNG && tmp._STRNGptr->empty())){
1029 	    int pr1=printcell_current_row(contextptr),pc1=printcell_current_col(contextptr);
1030 	    printcell_current_row(contextptr)=printcell_current_col(contextptr)=0;
1031 	    string s=printcell(makevecteur(vecteur(1,i),vecteur(1,j)),contextptr);
1032 	    printcell_current_row(contextptr)=pr1;
1033 	    printcell_current_col(contextptr)=pc1;
1034 	    return s;
1035 	  }
1036 	}
1037       }
1038     }
1039     return "";
1040   }
1041 
cb_Spread_goto(Fl_Widget * widg,void *)1042   void cb_Spread_goto(Fl_Widget* widg, void*) {
1043     // Find a spreadsheet in the brothers of widget (parent's children)
1044     Flv_Table_Gen * spread_ptr=find_table_brother(widg);
1045     const giac::context * contextptr = get_context(spread_ptr);
1046     if (!spread_ptr)
1047       return;
1048     Fl::focus(spread_ptr);
1049     Fl_Input * widget=dynamic_cast<Fl_Input *>(widg);
1050     gen g=undef;
1051     if (widget)
1052       g=parse_interval(widget->value());
1053     int r,c;
1054     if (iscell(g,c,r,contextptr) ){
1055       if (r>=spread_ptr->rows()||c>=spread_ptr->cols())
1056 	spread_ptr->resizesheet(max(r+1,spread_ptr->rows()),max(c+1,spread_ptr->cols()));
1057       // cerr << g << " " << r << " " << c << '\n';
1058       spread_ptr->row(r);
1059       spread_ptr->col(c);
1060       spread_ptr->select_start_row(r);
1061       spread_ptr->select_start_col(c);
1062       printcell_current_row(contextptr)=r;
1063       printcell_current_col(contextptr)=c;
1064       if (spread_ptr->input){
1065 	string s(spread_ptr->m[r][c][0].print(contextptr));
1066 	spread_ptr->input->value(s.c_str());
1067 	spread_ptr->input->position(s.size(),0);
1068       }
1069       return;
1070     }
1071     matrice m;
1072     if (iscell_range(g,spread_ptr->m,spread_ptr->selected,spread_ptr) ){
1073       g=extractmatricefromsheet(spread_ptr->selected);
1074       string s(g.print(contextptr));
1075       Fl::selection(*spread_ptr,s.c_str(),s.size());
1076       if (Xcas_help_output)
1077 	Xcas_help_output->value(s.c_str());
1078     }
1079   }
1080 
1081   // scan filename supposed to be a CSV data file
1082   // guess separator and newline character
csv_guess(const string & filename,char & sep,char & nl,char & decsep)1083   bool csv_guess(const string & filename,char & sep,char & nl,char & decsep){
1084     struct stat st;
1085     if (stat(filename.c_str(),&st)==ENOENT)
1086       return false;
1087     FILE * f=fopen(filename.c_str(),"r");
1088     if (!f)
1089       return false;
1090     size_t size=1,count=st.st_size;
1091     char data[count];
1092     fread(data,size,count,f);
1093     fclose(f);
1094     return giac::csv_guess(data,count,sep,nl,decsep);
1095   }
1096 
cb_Sheet_Input(Fl_Widget * widg,void *)1097   void cb_Sheet_Input(Fl_Widget* widg, void*) {
1098     Flv_Table_Gen * spread_ptr=find_table_brother(widg);
1099     if (!spread_ptr)
1100       return;
1101     context * contextptr=get_context(spread_ptr);
1102     Fl::focus(spread_ptr);
1103     if (spread_ptr && spread_ptr->editing){
1104       spread_ptr->editing=false;
1105       // cerr << "Mtrw edit end" << '\n';
1106       spread_ptr->row(spread_ptr->edit_row);
1107       spread_ptr->col(spread_ptr->edit_col);
1108     }
1109     spread_ptr->changed();
1110     int R=spread_ptr->row(),C=spread_ptr->col();
1111     string str(spread_ptr->input->value());
1112     gen g;
1113     try {
1114       g=gen(str,contextptr);
1115     }
1116     catch (std::runtime_error & e){
1117       cerr << e.what() << '\n';
1118     }
1119     // count number of newline
1120     unsigned strs=str.size();
1121     unsigned nlpos=str.find('\n');
1122     if (giac::first_error_line(contextptr)>0 && nlpos>0 && nlpos<strs-1){
1123       char nl,sep,decsep,eof=-1;
1124       // removed the test sep!=' '
1125       if (giac::csv_guess(str.c_str(),strs,sep,nl,decsep)){
1126 	if (str[strs-1]!=nl)
1127 	  str += nl;
1128 	istringstream i(str);
1129 	matrice M(csv2gen(i,sep,nl,decsep,eof,contextptr));
1130 	int nc=M.front()._VECTptr->size();
1131 	if (nc>=2 && ckmatrix(M,true)){
1132 	  makespreadsheetmatrice(M,contextptr); // in place modifications of value
1133 	  spread_ptr->paste(M);
1134 	  if (spread_ptr->move_right){
1135 	    C += nc-1;
1136 	    if (C<spread_ptr->cols()){
1137 	      spread_ptr->col(C);
1138 	    spread_ptr->enter_move();
1139 	    }
1140 	  }
1141 	  else {
1142 	    R += M.size()-1;
1143 	    if (R<spread_ptr->rows()){
1144 	      spread_ptr->row(R);
1145 	      spread_ptr->enter_move();
1146 	    }
1147 	  }
1148 	  return;
1149 	}
1150       }
1151     }
1152     int dofill=0;
1153     if ( (R>=0) && (C>=0) ){
1154       vecteur & v=*spread_ptr->m[R]._VECTptr;
1155       if (g.type==_SYMB){
1156          if ( (g._SYMBptr->sommet==at_tablefunc ) || (g._SYMBptr->sommet==at_tableseq) ) {
1157            if (g._SYMBptr->sommet==at_tablefunc)
1158              dofill=2;
1159            else
1160              dofill=1;
1161            spread_ptr->is_spreadsheet=true;
1162            // FIXME update_sheet_label();
1163            R=-1;
1164            g=protecteval(g,eval_level(contextptr),contextptr);
1165            spread_ptr->row(0);
1166          }
1167          else {
1168            if (!spread_ptr->is_spreadsheet || spread_ptr->matrix_fill_cells)
1169              g=protecteval(g,eval_level(contextptr),contextptr);
1170          }
1171       }
1172       if ( spread_ptr->matrix_fill_cells && g.type==_VECT){
1173         matrice & m=*g._VECTptr;
1174         if (!ckmatrix(m))
1175           m=vecteur(1,m);
1176         spread_ptr->paste(m);
1177         spread_ptr->redraw();
1178         Fl::focus(spread_ptr);
1179         spread_ptr->row(giacmin(R+m.size(),spread_ptr->rows()));
1180         if (dofill){
1181           spread_ptr->copy_down();
1182           if (dofill==2){
1183             spread_ptr->col(spread_ptr->col()+1);
1184             spread_ptr->copy_down();
1185           }
1186         }
1187         spread_ptr->select_start_row(spread_ptr->row());
1188         spread_ptr->select_start_col(spread_ptr->col());
1189 	spread_ptr->update_goto();
1190 	spread_ptr->update_input();
1191         return;
1192       }
1193       if ( (v[C].type==_VECT) && (v[C]._VECTptr->size()==3)){
1194 	v[C]._VECTptr->front()=spread_convert(g,R,C,contextptr);
1195 	if (!spread_ptr->is_spreadsheet)
1196 	  (*v[C]._VECTptr)[1]=g;
1197 	if (spread_ptr->spreadsheet_recompute)
1198           spread_ptr->spread_eval_interrupt();
1199 	else
1200 	  (*v[C]._VECTptr)[1]=g;
1201       }
1202       else
1203 	v[C]=g;
1204       if (spread_ptr->matrix_symmetry && spread_ptr->matrix_symmetry %2)
1205         g=-g;
1206       if (spread_ptr->matrix_symmetry && spread_ptr->matrix_symmetry/2)
1207         g=conj(g,contextptr);
1208       if (spread_ptr->matrix_symmetry && !spread_ptr->is_spreadsheet && (spread_ptr->rows()==spread_ptr->cols()) ){
1209         vecteur & v=*spread_ptr->m[C]._VECTptr;
1210         if ( (v[R].type==_VECT) && (v[R]._VECTptr->size()==3)){
1211 	  v[R]._VECTptr->front()=spread_convert(g,C,R,contextptr);
1212 	  (*v[R]._VECTptr)[1]=g;
1213         }
1214         else
1215 	  v[R]=g;
1216       }
1217       spread_ptr->enter_move();
1218     }
1219   }
1220 
1221 
cb_Tableur_Eval_Sheet(Fl_Widget * m,void *)1222    void cb_Tableur_Eval_Sheet(Fl_Widget * m , void*) {
1223     Flv_Table_Gen * tg=find_table_brother(m);
1224     if (tg)
1225       tg->spread_eval_interrupt();
1226   }
1227 
cb_Tableur_Init(Fl_Widget * m,void * param)1228    void cb_Tableur_Init(Fl_Widget * m , void*param) {
1229      Flv_Table_Gen * spread_ptr=find_table_brother(m);
1230      const giac::context * contextptr =get_context(spread_ptr);
1231      if (spread_ptr){
1232        protecteval(spread_ptr->init,eval_level(contextptr),contextptr);
1233        cb_Tableur_Eval_Sheet(m,param);
1234      }
1235    }
1236 
cb_Tableur_Value(Fl_Widget * m,void *)1237    void cb_Tableur_Value(Fl_Widget * m , void*) {
1238     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1239     const giac::context * contextptr =get_context(spread_ptr);
1240     if (spread_ptr){
1241       int R=spread_ptr->row(),C=spread_ptr->col();
1242       if (spread_ptr->m.size()>unsigned(R)){
1243 	gen g=spread_ptr->m[R];
1244 	if (g.type==_VECT && g._VECTptr->size()>unsigned(C)){
1245 	  g=(*g._VECTptr)[C];
1246 	  if (g.type==_VECT && g._VECTptr->size()>2)
1247 	    g=(*g._VECTptr)[1];
1248 	  spread_ptr->input->value(g.print(contextptr).c_str());
1249 	}
1250       }
1251     }
1252   }
1253 
1254   /*
1255    void cb_Tableur_LaTeX_Preview(Fl_Menu_* m , void*) {
1256     Flv_Table_Gen * tg=find_table_brother(m);
1257   }
1258 
1259    void cb_Tableur_LaTeX_Print(Fl_Menu_* m , void*) {
1260     Flv_Table_Gen * tg=find_table_brother(m);
1261   }
1262   */
1263 
1264    void cb_Tableur_Save(Fl_Widget* m , void*);
1265 
get_filename(string & tmp,const string & extension)1266   bool get_filename(string & tmp,const string & extension){
1267     for (;;){
1268       char * newfile = file_chooser(gettext("Save sheet"), ("*."+extension).c_str(), "");
1269       if ( (!newfile) || (!*newfile))
1270 	return false;
1271       tmp=newfile;
1272       //      tmp=remove_path(newfile);
1273       if (tmp.size()>1000)
1274 	tmp=tmp.substr(0,1000);
1275       tmp=remove_extension(tmp.c_str())+"."+extension;
1276       if (access(tmp.c_str(),R_OK))
1277 	return true;
1278       int i=fl_ask("%s",(tmp+gettext(": file exists. Overwrite?")).c_str());
1279       if (i==1)
1280 	return true;
1281     }
1282     return false;
1283   }
1284 
cb_Tableur_Graph2d(Fl_Widget * m,void *)1285    void cb_Tableur_Graph2d(Fl_Widget* m , void*) {
1286     Flv_Table_Gen * tg=find_table_brother(m);
1287     if (tg && tg->graph2d)
1288       tg->graph2d->window()->show();
1289   }
1290 
cb_Tableur_Graph3d(Fl_Widget * m,void *)1291    void cb_Tableur_Graph3d(Fl_Widget* m , void*) {
1292     Flv_Table_Gen * tg=find_table_brother(m);
1293     if (tg){
1294       if (tg->win3){
1295 	delete tg->graph3d;
1296 	delete tg->win3;
1297       }
1298       Fl_Group::current(0);
1299       tg->win3=new Fl_Window(tg->x()+10,tg->y()+10,2*tg->w()/3,2*tg->h()/3);
1300 #ifdef HAVE_LIBFLTK_GL
1301       tg->graph3d = new Graph3d(0,0,tg->win3->w(),tg->win3->h(),"",0);
1302       tg->graph3d->ylegende=1.5;
1303       tg->win3->end();
1304       tg->win3->resizable(tg->win3);
1305       tg->win3->show();
1306       tg->update_spread_graph();
1307 #endif
1308     }
1309   }
1310 
cb_Tableur_Save_as(Fl_Widget * m,void *)1311    void cb_Tableur_Save_as(Fl_Widget* m , void*) {
1312     Flv_Table_Gen * tg=find_table_brother(m);
1313     if (!tg)
1314       return;
1315     string tmp;
1316     if (!get_filename(tmp,"tab"))
1317       return ;
1318     if (tg->filename)
1319       delete tg->filename;
1320     tg->filename = new string(tmp);
1321     if (tg->filename){
1322       gen tmp(remove_extension(remove_path(*tg->filename)),context0);
1323       if (tmp.type==_IDNT && !is_undef(tmp)){
1324 	tg->name=tmp;
1325 	tg->update_name();
1326       }
1327       tg->prefix_filename="Save "+remove_path(*tg->filename);
1328       if (Tableur_Group * gr=dynamic_cast<Tableur_Group *>(tg->parent())){
1329 	gr->fname->label(tg->prefix_filename.c_str());
1330 	gr->fname->show();
1331       }
1332     }
1333     cb_Tableur_Save(m,0);
1334   }
1335 
1336 
cb_Tableur_Save_mathml(Fl_Menu_ * m,void *)1337    void cb_Tableur_Save_mathml(Fl_Menu_* m , void*) {
1338     Flv_Table_Gen * tg=find_table_brother(m);
1339     if (!tg) return;
1340     const giac::context * contextptr = get_context(tg);
1341     string tmp;
1342     if (!get_filename(tmp,"htm"))
1343       return ;
1344     ofstream of(tmp.c_str());
1345     if (!of){
1346       fl_message("%s","Write error");
1347       return;
1348     }
1349     of << mathml_preamble << '\n';
1350     int formule=tg->is_spreadsheet?0:1;
1351     of << spread2mathml(tg->m,formule,contextptr);
1352     of << mathml_end << '\n';
1353   }
1354 
cb_Tableur_Save_CSV(Fl_Menu_ * m,void *)1355    void cb_Tableur_Save_CSV(Fl_Menu_* m , void*) {
1356     Flv_Table_Gen * tg=find_table_brother(m);
1357     if (!tg) return;
1358     string tmp;
1359     if (!get_filename(tmp,"csv"))
1360       return ;
1361     ofstream of(tmp.c_str());
1362     if (!of){
1363       fl_message("%s","Write error");
1364       return;
1365     }
1366     matrice M(extractmatricefromsheet(tg->m));
1367     const_iterateur it=M.begin(),itend=M.end();
1368     for (;it!=itend;++it){
1369       if (it->type==_VECT){
1370 	const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
1371 	for (;jt!=jtend;++jt){
1372 	  of << *jt << ";";
1373 	}
1374 	of << '\n';
1375       }
1376     }
1377     of << '\n';
1378     of.close();
1379   }
1380 
1381 
cb_Tableur_Save(Fl_Widget * m,void *)1382    void cb_Tableur_Save(Fl_Widget * m , void*) {
1383     Flv_Table_Gen * tg=find_table_brother(m);
1384     if (!tg) return;
1385     if (!tg->filename)
1386       cb_Tableur_Save_as(m,0);
1387     if (tg->filename){
1388       ofstream of(tg->filename->c_str());
1389       if (!of){
1390 	fl_message("%s","Write error");
1391 	return;
1392       }
1393       if (tg->is_spreadsheet)
1394 	of << gen(tg->m,_SPREAD__VECT) << '\n';
1395       else
1396 	of << gen(extractmatricefromsheet(tg->m)) << '\n';
1397       of.close();
1398       tg->changed_ = false;
1399     }
1400     tg->update_status();
1401   }
1402 
cb_Tableur_Save_var(Fl_Widget * m,void *)1403    void cb_Tableur_Save_var(Fl_Widget* m , void*) {
1404     Flv_Table_Gen * tg=find_table_brother(m);
1405     if (!tg) return;
1406     const giac::context * contextptr = get_context(tg);
1407     if (tg){
1408       matrice mat=extractmatricefromsheet(tg->selected);
1409       if (mat.empty() && tg->row()<tg->rows() && tg->col() < tg->cols()){
1410 	gen res=tg->m[tg->row()][tg->col()];
1411 	if (res.type==_VECT && res._VECTptr->size()==3)
1412 	  res=(*res._VECTptr)[1];
1413 	mat=vecteur(1,vecteur(1,res));
1414       }
1415       const char * varname = fl_input(gettext("Variable name?"));
1416       if (varname){
1417 	gen g(varname,contextptr);
1418 	if (g.type!=_IDNT){
1419 	  fl_message("%s",(g.print(contextptr)+gettext("is not a variable name")).c_str());
1420 	  cb_Tableur_Save_var(m,0);
1421 	}
1422 	protecteval(symb_sto(mat,g),eval_level(contextptr),contextptr);
1423       }
1424     }
1425   }
1426 
1427   // Insure that all elements of m that are vectors have length <= 3
spread_ck(matrice & m)1428   void spread_ck(matrice & m){
1429     iterateur it=m.begin(),itend=m.end();
1430     for (;it!=itend;++it){
1431       if (it->type==_VECT){
1432 	iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
1433 	for (;jt!=jtend;++jt){
1434 	  if (jt->type==_VECT && jt->_VECTptr->size()>3){
1435 	    *jt=makevecteur(jt->_VECTptr->front(),vecteur(jt->_VECTptr->begin()+1,jt->_VECTptr->end()-1),jt->_VECTptr->back());
1436 	  }
1437 	}
1438       }
1439     }
1440   }
1441 
tableur_insert(Flv_Table_Gen * tg)1442   std::string tableur_insert(Flv_Table_Gen * tg){
1443     char * newfile = load_file_chooser(gettext("Insert sheet"), "*.tab", "",0,false);
1444     if (!newfile || file_not_available(newfile))
1445       return "";
1446     ifstream inf(newfile);
1447     const giac::context * contextptr = get_context(tg);
1448     gen value(read1arg_from_stream(inf,contextptr));
1449     if (!ckmatrix(value,true))
1450       return "";
1451     spread_ck(*value._VECTptr); // in place modifications of value
1452     tg->paste(*value._VECTptr);
1453     return remove_path(remove_extension(newfile));
1454   }
1455 
cb_Tableur_Insert(Fl_Menu_ * m,void *)1456    void cb_Tableur_Insert(Fl_Menu_* m , void*) {
1457     Flv_Table_Gen * tg=find_table_brother(m);
1458     if (!tg) return;
1459     tableur_insert(tg);
1460   }
1461 
cb_Tableur_Insert_CSV(Fl_Menu_ * m,void *)1462    void cb_Tableur_Insert_CSV(Fl_Menu_* m , void*) {
1463     Flv_Table_Gen * tg=find_table_brother(m);
1464     if (!tg) return;
1465     const giac::context * contextptr = get_context(tg);
1466     char * newfile = load_file_chooser(gettext("Insert CSV sheet"), "*.csv", "",0,false);
1467     if (!newfile || file_not_available(newfile))
1468       return;
1469     char sep=';',nl='\n',decsep=',';
1470     csv_guess(newfile,sep,nl,decsep);
1471     static Fl_Window * w = 0;
1472     static Fl_Input * separator=0, * newline=0,*decimal_sep=0,*end_file=0; // field separator, newline, decimal sep, end of file
1473     static Fl_Check_Button* import_syntax=0;
1474     static Fl_Return_Button * button0 = 0 ;
1475     static Fl_Button * button1 =0;
1476     if (!w){
1477 #ifdef IPAQ
1478       int dx=240, dy=300;
1479 #else
1480       int dx=300, dy=120;
1481 #endif
1482       Fl_Group::current(0);
1483       w=new Fl_Window(dx,dy);
1484       separator=new Fl_Input(dx/4,2,dx/4-2,dy/4-4,gettext("Separator"));
1485       separator->tooltip(gettext("One character used to separate fields, like ; Use ^I for tab"));
1486       newline=new Fl_Input(3*dx/4,2,dx/4-2,dy/4-4,gettext("Newline"));
1487       newline->tooltip(gettext("One character used to separate lines, like <return> Use ^I for tab"));
1488       decimal_sep=new Fl_Input(dx/4,2+dy/4,dx/4-2,dy/4-4,gettext("Decimal"));
1489       decimal_sep->tooltip(gettext("One character used for decimal digit separator, like . or ,"));
1490       end_file=new Fl_Input(3*dx/4,2+dy/4,dx/4-2,dy/4-4,gettext("Endfile"));
1491       end_file->tooltip(gettext("Stop reading at first occurence of this character, leave blank for none"));
1492       import_syntax = new Fl_Check_Button(dx/4,2+2*dy/4,dx/4-2,dy/4-4,gettext("Start row=1"));
1493       import_syntax->value(1);
1494       button0 = new Fl_Return_Button(2,2+3*dy/4,dx/2-4,dy/4-4);
1495       button0->shortcut(0xff0d);
1496       button0->label(gettext("OK"));
1497       button1 = new Fl_Button(dx/2+2,2+3*dy/4,dx/2-4,dy/4-4);
1498       button1->shortcut(0xff1b);
1499       button1->label(gettext("Cancel"));
1500       w->end();
1501       w->resizable(w);
1502       w->label(gettext("CSV Import filter"));
1503     }
1504     // Guess separator and newline values from file scanning
1505     separator->value(string(1,sep).c_str());
1506     newline->value(string(1,nl).c_str());
1507     decimal_sep->value(string(1,decsep).c_str());
1508     int r=-1;
1509     w->set_modal();
1510     w->show();
1511     autosave_disabled=true;
1512     w->hotspot(w);
1513     Fl::focus(separator);
1514     for (;;) {
1515       Fl_Widget *o = Fl::readqueue();
1516       if (!o) Fl::wait();
1517       else {
1518 	if (o == button0) {r = 0; break;}
1519 	if (o == button1) {r = 1; break;}
1520 	if (o == w) { r=1; break; }
1521       }
1522     }
1523     autosave_disabled=false;
1524     w->hide();
1525     if (!r){
1526       ifstream i(newfile);
1527       char sep=';',nl='\n',decsep=',',eof=0;
1528       if (strlen(separator->value()) && separator->value()[0]){
1529 	if (separator->value()[1])
1530 	  sep=separator->value()[1]-64;
1531 	else
1532 	  sep=separator->value()[0];
1533       }
1534       if (strlen(newline->value()) && newline->value()[0]){
1535 	if (newline->value()[1])
1536 	  nl=newline->value()[1]-64;
1537 	else
1538 	  nl=newline->value()[0];
1539       }
1540       if (decimal_sep->value()[0])
1541 	decsep=decimal_sep->value()[0];
1542       if (end_file->value()[0])
1543 	eof=end_file->value()[0];
1544       int save_maple_mode=xcas_mode(contextptr);
1545       xcas_mode(contextptr)=import_syntax->value();
1546       matrice M(csv2gen(i,sep,nl,decsep,eof,contextptr));
1547       if (!ckmatrix(M,true))
1548 	return;
1549       context * contextptr=get_context(tg);
1550       makespreadsheetmatrice(M,contextptr); // in place modifications of value
1551       tg->paste(M);
1552       xcas_mode(contextptr)=save_maple_mode;
1553     }
1554   }
1555 
cb_Tableur_Preview(Fl_Menu_ * m,void *)1556    void cb_Tableur_Preview(Fl_Menu_* m , void*) {
1557     Flv_Table_Gen * tg=find_table_brother(m);
1558     if (!tg) return;
1559     widget_ps_print(tg,tg->filename?*tg->filename:"table",false);
1560   }
1561 
cb_Tableur_Print(Fl_Menu_ * m,void *)1562    void cb_Tableur_Print(Fl_Menu_* m , void*) {
1563     Flv_Table_Gen * tg=find_table_brother(m);
1564     if (!tg) return;
1565     widget_print(tg);
1566   }
1567 
cb_Tableur_Copy_Cell(Fl_Menu_ * m,void *)1568    void cb_Tableur_Copy_Cell(Fl_Menu_* m , void*) {
1569     Flv_Table_Gen * tg=find_table_brother(m);
1570     if (!tg) return;
1571     tg->copy();
1572   }
1573 
cb_Tableur_Copy_Right(Fl_Menu_ * m,void *)1574    void cb_Tableur_Copy_Right(Fl_Menu_* m , void*) {
1575     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1576     if (!spread_ptr) return;
1577     spread_ptr->copy_right();
1578   }
1579 
cb_Tableur_Copy_Down(Fl_Menu_ * m,void *)1580    void cb_Tableur_Copy_Down(Fl_Menu_* m , void*) {
1581     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1582     if (!spread_ptr) return;
1583     spread_ptr->copy_down();
1584   }
1585 
cb_Tableur_DelRow(Fl_Menu_ * m,void *)1586    void cb_Tableur_DelRow(Fl_Menu_* m , void*) {
1587     Flv_Table_Gen * tg=find_table_brother(m);
1588     if (!tg) return;
1589     tg->spread_erase(1,0);
1590   }
1591 
cb_Tableur_Del(Fl_Menu_ * m,void *)1592    void cb_Tableur_Del(Fl_Menu_* m , void*) {
1593     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1594     if (!spread_ptr) return;
1595     bool tmp=spread_ptr->is_spreadsheet;
1596     spread_ptr->is_spreadsheet=false;
1597     spread_ptr->blank(0,spread_ptr->rows(),0,spread_ptr->cols());
1598     spread_ptr->is_spreadsheet=tmp;
1599   }
1600 
cb_Tableur_DelRows(Fl_Menu_ * m,void *)1601    void cb_Tableur_DelRows(Fl_Menu_* m , void*) {
1602     Flv_Table_Gen * tg=find_table_brother(m);
1603     if (!tg) return;
1604     tg->erase_row_col(0);
1605   }
1606 
cb_Tableur_DelCol(Fl_Menu_ * m,void *)1607    void cb_Tableur_DelCol(Fl_Menu_* m , void*) {
1608     Flv_Table_Gen * tg=find_table_brother(m);
1609     if (!tg) return;
1610     tg->spread_erase(0,1);
1611   }
1612 
cb_Tableur_DelCols(Fl_Menu_ * m,void *)1613    void cb_Tableur_DelCols(Fl_Menu_* m , void*) {
1614     Flv_Table_Gen * tg=find_table_brother(m);
1615     if (!tg) return;
1616     tg->erase_row_col(1);
1617   }
1618 
cb_Tableur_InsRow(Fl_Menu_ * m,void *)1619    void cb_Tableur_InsRow(Fl_Menu_* m , void*) {
1620     Flv_Table_Gen * tg=find_table_brother(m);
1621     if (!tg) return;
1622     tg->spread_insert(1,0);
1623   }
1624 
cb_Tableur_InsCol(Fl_Menu_ * m,void *)1625    void cb_Tableur_InsCol(Fl_Menu_* m , void*) {
1626     Flv_Table_Gen * tg=find_table_brother(m);
1627     if (!tg) return;
1628     tg->spread_insert(0,1);
1629   }
1630 
cb_Tableur_InsCol_End(Fl_Menu_ * m,void *)1631    void cb_Tableur_InsCol_End(Fl_Menu_* m , void*) {
1632     Flv_Table_Gen * tg=find_table_brother(m);
1633     if (!tg) return;
1634     tg->addcolatend();
1635   }
1636 
cb_Tableur_InsRow_End(Fl_Menu_ * m,void *)1637    void cb_Tableur_InsRow_End(Fl_Menu_* m , void*) {
1638     Flv_Table_Gen * tg=find_table_brother(m);
1639     if (!tg) return;
1640     tg->addrowatend();
1641   }
1642 
cb_Tableur_MoveRight(Fl_Menu_ * m,void *)1643    void cb_Tableur_MoveRight(Fl_Menu_* m , void*) {
1644     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1645     if (!spread_ptr) return;
1646     spread_ptr->move_on_enter(FLV_MOVE_ON_ENTER_COL_ROW);
1647     spread_ptr->move_right=true;
1648     spread_ptr->update_status();
1649   }
1650 
cb_Tableur_MoveDown(Fl_Menu_ * m,void *)1651    void cb_Tableur_MoveDown(Fl_Menu_* m , void*) {
1652     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1653     if (!spread_ptr) return;
1654     spread_ptr->move_on_enter(FLV_MOVE_ON_ENTER_ROW_COL);
1655     spread_ptr->move_right=false;
1656     spread_ptr->update_status();
1657   }
1658 
cb_Tableur_FillSelection(Fl_Menu_ * m,void *)1659    void cb_Tableur_FillSelection(Fl_Menu_* m , void*) {
1660     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1661     if (!spread_ptr) return;
1662     spread_ptr->copy_first_in_selection();
1663   }
1664 
cb_Tableur_Col_Larger(Fl_Menu_ * m,void *)1665    void cb_Tableur_Col_Larger(Fl_Menu_* m , void*) {
1666     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1667     if (!spread_ptr) return;
1668     spread_ptr->col_width(spread_ptr->col_width(spread_ptr->col())+5,spread_ptr->col());
1669   }
1670 
cb_Tableur_Col_Smaller(Fl_Menu_ * m,void *)1671    void cb_Tableur_Col_Smaller(Fl_Menu_* m , void*) {
1672     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1673     if (!spread_ptr) return;
1674     spread_ptr->col_width(spread_ptr->col_width(spread_ptr->col())-5,spread_ptr->col());
1675   }
1676 
cb_Tableur_Fill0(Fl_Menu_ * m,void *)1677    void cb_Tableur_Fill0(Fl_Menu_* m , void*) {
1678     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1679     if (!spread_ptr) return;
1680     bool tmp=spread_ptr->is_spreadsheet;
1681     spread_ptr->is_spreadsheet=false;
1682     // int r1=spread_ptr->select_start_row(),r2=spread_ptr->row(),c1=spread_ptr->select_start_col(),c2=spread_ptr->col();
1683     // spread_ptr->blank(r1,r2,c1,c2);
1684     spread_ptr->blank();
1685     spread_ptr->is_spreadsheet=tmp;
1686   }
1687 
tableur_insert_replace(Flv_Table_Gen * spread_ptr,const string & s)1688   void tableur_insert_replace(Flv_Table_Gen * spread_ptr,const string & s){
1689     if (!spread_ptr) return;
1690     if (!spread_ptr->editing){
1691       spread_ptr->edit_row=spread_ptr->row();
1692       spread_ptr->edit_col=spread_ptr->col();
1693       spread_ptr->editing=true;
1694     }
1695     spread_ptr->input->insert_replace(s,true);
1696     spread_ptr->input->position(spread_ptr->input->mark(),spread_ptr->input->mark());
1697     Fl::focus(spread_ptr->input);
1698   }
1699 
1700 
coltocolname(int i)1701   std::string coltocolname(int i){
1702     string tmp;
1703     for(int j=0;;++j){
1704       tmp=char('A'+i%26-(j!=0))+tmp;
1705       i=i/26;
1706       if (!i)
1707 	break;
1708     }
1709     return tmp;
1710   }
1711 
1712   // return true if s parsed has identifiers which are cell names
has_cell(const string & s,gen & cell,GIAC_CONTEXT)1713   bool has_cell(const string & s,gen & cell,GIAC_CONTEXT){
1714     gen g(s,contextptr);
1715     vecteur l(lidnt(g));
1716     int ls=l.size(),r,c;
1717     for (int i=0;i<ls;++i){
1718       if (iscell((cell=l[i]),r,c,contextptr))
1719 	return true;
1720     }
1721     return false;
1722   }
1723 
1724   int xcas_integration_method=0;
1725   Fl_Output * Xcas_Methodes_Output=0;
cb_Xcas_Methodes_builtin(Fl_Menu_ * m,void *)1726   void cb_Xcas_Methodes_builtin(Fl_Menu_* m , void*) {
1727     xcas_integration_method=0;
1728     if (Xcas_Methodes_Output)
1729       Xcas_Methodes_Output->value(gettext("builtin"));
1730   }
1731 
cb_Xcas_Methodes_right_rectangle(Fl_Menu_ * m,void *)1732   void cb_Xcas_Methodes_right_rectangle(Fl_Menu_* m , void*) {
1733     xcas_integration_method=1;
1734     if (Xcas_Methodes_Output)
1735       Xcas_Methodes_Output->value(gettext("right rectangle"));
1736   }
1737 
cb_Xcas_Methodes_left_rectangle(Fl_Menu_ * m,void *)1738   void cb_Xcas_Methodes_left_rectangle(Fl_Menu_* m , void*) {
1739     xcas_integration_method=2;
1740     if (Xcas_Methodes_Output)
1741       Xcas_Methodes_Output->value(gettext("left rectangle"));
1742   }
1743 
cb_Xcas_Methodes_middle_point(Fl_Menu_ * m,void *)1744   void cb_Xcas_Methodes_middle_point(Fl_Menu_* m , void*) {
1745     xcas_integration_method=3;
1746     if (Xcas_Methodes_Output)
1747       Xcas_Methodes_Output->value(gettext("middle point"));
1748   }
1749 
cb_Xcas_Methodes_trapezoid(Fl_Menu_ * m,void *)1750   void cb_Xcas_Methodes_trapezoid(Fl_Menu_* m , void*) {
1751     xcas_integration_method=4;
1752     if (Xcas_Methodes_Output)
1753       Xcas_Methodes_Output->value(gettext("trapezoid"));
1754   }
1755 
1756   Fl_Menu_Item Xcas_Menu_Methodes[] = {
1757     {gettext("builtin"), 0,  (Fl_Callback*)cb_Xcas_Methodes_builtin, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
1758     {gettext("right_rectangle"), 0,  (Fl_Callback*)cb_Xcas_Methodes_right_rectangle, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
1759     {gettext("left_rectangle"), 0,  (Fl_Callback*)cb_Xcas_Methodes_left_rectangle, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
1760     {gettext("middle_point"), 0,  (Fl_Callback*)cb_Xcas_Methodes_middle_point, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
1761     {gettext("trapezoid"), 0,  (Fl_Callback*)cb_Xcas_Methodes_trapezoid, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
1762     {0,0,0,0,0,0,0,0,0}
1763   };
1764 
1765   // type 1= plotfunc 3d, 0 plotfunc 2d, 2 plotarea
tablefunc_dialog(Fl_Widget * spread_ptr,std::string & arg,bool plot,int type,const string & title)1766   bool tablefunc_dialog(Fl_Widget * spread_ptr,std::string & arg,bool plot,int type,const string & title){
1767     static Fl_Window * w = 0;
1768     static Fl_Input *fcn=0, *fcn3d=0,* varname=0, * varnamey=0,*target=0;
1769     static Fl_Value_Input * xmin=0,*xstep=0,*xmax=0;
1770     static Fl_Value_Input * ymin=0,*ystep=0,*ymax=0;
1771     static Fl_Return_Button * button0 = 0 ;
1772     static Fl_Menu_Button * methode=0;
1773     static Fl_Button * button1 =0;
1774     static Line_Type * ltres=0;
1775     if (!w){
1776 #ifdef IPAQ
1777       int dx=240,dy=300;
1778 #else
1779       int dx=(spread_ptr?20*spread_ptr->labelsize():400),
1780 	dy=spread_ptr?8*spread_ptr->labelsize():300;
1781 #endif
1782       int lignes=5;
1783       Fl_Group::current(0);
1784       w=new Fl_Window(dx,dy);
1785       ltres = new Line_Type(2,2,dx/15,dy/lignes-4,_MAGENTA+_FILL_POLYGON);
1786       ltres->show_pnt(true);
1787       ltres->show_poly(true);
1788       ltres->tooltip(gettext("Plot style (select a point type or width for dotted plot)"));
1789       fcn=new Fl_Input(dx/2,2,dx/2-4,dy/lignes-4,gettext("Expression"));
1790       fcn->value("x^2");
1791       fcn->tooltip(gettext("Expression of the function (e.g sin(x))"));
1792       fcn3d=new Fl_Input(dx/2,2,dx/2-4,dy/lignes-4,gettext("Expression"));
1793       fcn3d->value("x^2-y^2");
1794       fcn3d->tooltip(gettext("Expression of the function (e.g x-y^2)"));
1795       varname=new Fl_Input(dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("1st var"));
1796       varname->value("x");
1797       varname->tooltip(gettext("Independant variable name (e.g x)"));
1798       varnamey=new Fl_Input(3*dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("2nd var"));
1799       varnamey->value("y");
1800       varnamey->tooltip(gettext("Second independant variable name (e.g y)"));
1801       xmin = new Fl_Value_Input(dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xmin"));
1802       xmin->value(-4);
1803       xmin->step(0.5);
1804       xmin->tooltip(gettext("Minimal value for 1st independant variable"));
1805       xstep = new Fl_Value_Input(3*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xstep"));
1806       xstep->value(0.5);
1807       xstep->step(0.01);
1808       xstep->tooltip(gettext("Discretization step for 1st independant variable"));
1809       xmax = new Fl_Value_Input(5*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xmax"));
1810       xmax->value(4);
1811       xmax->step(0.5);
1812       xmax->tooltip(gettext("Maximal value for 1st independant variable"));
1813       target = new Fl_Input(dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("Target"));
1814       target->tooltip(gettext("Name of the first of two columns that will be overwritten by the tablefunc"));
1815       ymin = new Fl_Value_Input(dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ymin"));
1816       ymin->value(-4);
1817       ymin->step(0.5);
1818       ymin->tooltip(gettext("Minimal value for 2nd independant variable"));
1819       ystep = new Fl_Value_Input(3*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ystep"));
1820       ystep->value(0.5);
1821       ystep->step(0.01);
1822       ystep->tooltip(gettext("Discretization step for 2nd independant variable"));
1823       ymax = new Fl_Value_Input(5*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ymax"));
1824       ymax->value(4);
1825       ymax->step(0.5);
1826       ymin->tooltip(gettext("Maximal value for 2nd independant variable"));
1827       methode = new Fl_Menu_Button(0,2+3*dy/lignes,dx/3-2,dy/lignes-4,gettext("Choose"));
1828       methode->menu(Xcas_Menu_Methodes);
1829       Xcas_Methodes_Output = new Fl_Output(4*dx/6,2+3*dy/lignes,dx/3-2,dy/lignes-4,gettext("int. method"));
1830       Xcas_Methodes_Output->value(gettext("builtin"));
1831       button0 = new Fl_Return_Button(2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
1832       button0->shortcut(0xff0d);
1833       button0->label(gettext("OK"));
1834       button1 = new Fl_Button(dx/2+2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
1835       button1->shortcut(0xff1b);
1836       button1->label(gettext("Cancel"));
1837       w->end();
1838       change_group_fontsize(w,spread_ptr?spread_ptr->labelsize():14);
1839       w->resizable(w);
1840     }
1841     w->label(title.c_str());
1842     Flv_Table_Gen * tbl=dynamic_cast<Flv_Table_Gen *>(spread_ptr);
1843     if (tbl)
1844       target->value(coltocolname(tbl->col()).c_str());
1845     if (plot){
1846       target->hide();
1847     }
1848     else {
1849       target->show();
1850     }
1851     if (type==2){
1852       methode->show();
1853       Xcas_Methodes_Output->show();
1854     }
1855     else {
1856       methode->hide();
1857       Xcas_Methodes_Output->hide();
1858     }
1859     if (type==1){
1860       ymax->show();
1861       ymin->show();
1862       ystep->show();
1863       varnamey->show();
1864       fcn->hide();
1865       fcn3d->show();
1866     }
1867     else {
1868       ymax->hide();
1869       ymin->hide();
1870       ystep->hide();
1871       varnamey->hide();
1872       fcn->show();
1873       fcn3d->hide();
1874     }
1875     int r=-1;
1876     w->set_modal();
1877     w->show();
1878     autosave_disabled=true;
1879     w->hotspot(w);
1880     Fl::focus(varname);
1881     for (;;) {
1882       Fl_Widget *o = Fl::readqueue();
1883       if (!o) Fl::wait();
1884       else {
1885 	if (o==ltres){
1886 	  int i=ltres->line_type();
1887 	  bool formel=false,untranslate=false,approx=false;
1888 	  change_line_type(i,true,approx,"",fcn3d->visible(),formel,untranslate,false,spread_ptr?spread_ptr->labelsize():14);
1889 	  ltres->line_type(i);
1890 	}
1891 	if (o == button0) {r = 0; break;}
1892 	if (o == button1) {r = 1; break;}
1893 	if (o == w) { r=1; break; }
1894       }
1895     }
1896     autosave_disabled=false;
1897     w->hide();
1898     if (!r){
1899       if (tbl){
1900 	int r;
1901 	if (!alphaposcell(target->value(),r)){
1902 	  fl_alert("%s","Invalid column");
1903 	  return false;
1904 	}
1905 	tbl->col(r);
1906       }
1907       arg=(type==1?fcn3d:fcn)->value();
1908       gen cell;
1909       if (has_cell(arg,cell,context0)){
1910 	fl_alert("%s",("Expression contains a cell name "+cell.print()).c_str());
1911 	return false;
1912       }
1913       arg += string(",");
1914       if (plot){
1915 	if (type==1){
1916 	  arg += "["+string(varname->value())+"="+print_DOUBLE_(xmin->value())+".."+print_DOUBLE_(xmax->value()) + string(",")+varnamey->value()+string("=")+print_DOUBLE_(ymin->value())+".."+print_DOUBLE_(ymax->value())+"],xstep="+print_DOUBLE_(xstep->value())+",ystep="+print_DOUBLE_(ystep->value())+",display="+print_color(ltres->line_type());
1917 	}
1918 	else {
1919 	  arg += string(varname->value())+"="+print_DOUBLE_(xmin->value())+".."+print_DOUBLE_(xmax->value());
1920 	  if (type==2 && xcas_integration_method){
1921 	    arg += ","+print_INT_(int((xmax->value()-xmin->value())/xstep->value()));
1922 	    switch (xcas_integration_method){
1923 	    case 1:
1924 	      arg += ",right_rectangle";
1925 	      break;
1926 	    case 2:
1927 	      arg += ",left_rectangle";
1928 	      break;
1929 	    case 3:
1930 	      arg += ",middle_point";
1931 	      break;
1932 	    case 4:
1933 	      arg += ",trapezoid";
1934 	      break;
1935 	    }
1936 	  }
1937 	  else
1938 	    arg += ",xstep="+print_DOUBLE_(xstep->value());
1939 	  arg += ",display="+print_color(ltres->line_type());
1940 	}
1941       }
1942       else
1943 	arg += string(varname->value())+","+print_DOUBLE_(xmin->value())+","+print_DOUBLE_(xstep->value())+","+print_DOUBLE_(xmax->value())+",display="+print_color(ltres->line_type());
1944       return true;
1945     }
1946     return false;
1947   }
1948 
cb_Tableur_Tablefunc(Fl_Menu_ * m,void *)1949    void cb_Tableur_Tablefunc(Fl_Menu_* m , void*) {
1950     Flv_Table_Gen * spread_ptr=find_table_brother(m);
1951     if (!spread_ptr) return;
1952     string arg;
1953     if (spread_ptr && tablefunc_dialog(spread_ptr,arg,false,0,gettext("Table of value of a function"))){
1954       arg="tablefunc("+arg+")";
1955       spread_ptr->input->value("");
1956       tableur_insert_replace(spread_ptr,arg);
1957       Tableur_Group * gr = dynamic_cast<Tableur_Group *>(spread_ptr->parent());
1958       if (gr && !(gr->disposition & 2) && !spread_ptr->graph2d->window()->visible() ){
1959 	gr->disposition |= 2;
1960 	gr->resize2();
1961       }
1962       spread_ptr->input->do_callback();
1963       // browser_help(gen("tablefunc"),language(get_context(spread_ptr)));
1964     }
1965   }
1966 
random_dialog(Fl_Widget * spread_ptr,gen & arg,double & Xmin,double & Xmax,bool & intg,bool & once)1967   bool random_dialog(Fl_Widget * spread_ptr,gen & arg,double & Xmin,double & Xmax,bool & intg,bool & once){
1968     static Fl_Window * w = 0;
1969     static Fl_Input *target=0;
1970     static Fl_Value_Input *xmin=0,*xmax=0;
1971     static Fl_Check_Button * intg_button=0, * once_button=0;
1972     static Fl_Return_Button * button0 = 0 ;
1973     static Fl_Button * button1 =0;
1974     if (!w){
1975       int lignes=4;
1976 #ifdef IPAQ
1977       int dx=240,dy=300;
1978 #else
1979       int dx=(spread_ptr?15*spread_ptr->labelsize():240),
1980 	dy=spread_ptr?8*spread_ptr->labelsize():300;
1981 #endif
1982       Fl_Group::current(0);
1983       w=new Fl_Window(dx,dy);
1984       target=new Fl_Input(dx/2,2,dx/2-2,dy/lignes-4,gettext("Target cell range"));
1985       target->tooltip(gettext("Target cell range will be filled by random numbers, e.g. A1:A8"));
1986       xmin=new Fl_Value_Input(dx/4,2+dy/lignes,dx/4-2,dy/lignes-4,gettext("x-"));
1987       xmin->value(1);
1988       xmin->tooltip(gettext("Minimal value"));
1989       xmax = new Fl_Value_Input(dx/2+dx/4,2+dy/lignes,dx/4-2,dy/lignes-4,gettext("x+"));
1990       xmax->value(6);
1991       xmax->tooltip(gettext("Maximal value"));
1992       intg_button=new Fl_Check_Button(4, 2+2*dy/lignes,dx/4,dy/lignes-4,gettext("integers"));
1993       intg_button->tooltip(gettext("Real or integers"));
1994       intg_button->down_box(FL_DOWN_BOX);
1995       intg_button->value(true);
1996       once_button=new Fl_Check_Button(dx/2+4, 2+2*dy/lignes,dx/4,dy/lignes-4,gettext("static"));
1997       once_button->tooltip(gettext("Immediate static value or formula reevaled each time"));
1998       once_button->down_box(FL_DOWN_BOX);
1999       once_button->value(true);
2000       button0 = new Fl_Return_Button(2,2+(lignes-1)*dy/lignes,dx/2-4,dy/lignes-4);
2001       button0->shortcut(0xff0d);
2002       button0->label(gettext("OK"));
2003       button1 = new Fl_Button(dx/2+2,2+(lignes-1)*dy/lignes,dx/2-4,dy/lignes-4);
2004       button1->shortcut(0xff1b);
2005       button1->label(gettext("Cancel"));
2006       w->end();
2007       change_group_fontsize(w,spread_ptr?spread_ptr->labelsize():14);
2008       w->resizable(w);
2009     }
2010     w->label("Random numbers");
2011     Flv_Table_Gen * tbl=dynamic_cast<Flv_Table_Gen *>(spread_ptr);
2012     if (tbl && strlen(tbl->_goto->value()))
2013       target->value(tbl->_goto->value());
2014     int r=-1;
2015     w->set_modal();
2016     w->show();
2017     autosave_disabled=true;
2018     w->hotspot(w);
2019     Fl::focus(target);
2020     for (;;) {
2021       Fl_Widget *o = Fl::readqueue();
2022       if (!o) Fl::wait();
2023       else {
2024 	if (o == button0) {r = 0; break;}
2025 	if (o == button1) {r = 1; break;}
2026 	if (o == w) { r=1; break; }
2027       }
2028     }
2029     autosave_disabled=false;
2030     w->hide();
2031     if (r==1)
2032       return false;
2033     intg=intg_button->value();
2034     once=once_button->value();
2035     arg=parse_interval(target->value());
2036     Xmin=xmin->value();
2037     Xmax=xmax->value();
2038     return true;
2039   }
2040 
tableseq_dialog(Fl_Widget * spread_ptr,std::string & arg,bool plot,const string & title,std::string & u0param)2041   bool tableseq_dialog(Fl_Widget * spread_ptr,std::string & arg,bool plot,const string & title,std::string & u0param){
2042     static Fl_Window * w = 0;
2043     static Fl_Input *fcn=0, * varname=0;
2044     static Fl_Value_Input *xmin=0,*xmax=0;
2045     static Fl_Input *u0name=0,* u0=0,* target=0;
2046     static Fl_Value_Input * nterms=0;
2047     static Fl_Return_Button * button0 = 0 ;
2048     static Fl_Button * button1 =0;
2049     if (!w){
2050       int lignes=5;
2051 #ifdef IPAQ
2052       int dx=240,dy=300;
2053 #else
2054       int dx=(spread_ptr?15*spread_ptr->labelsize():240),
2055 	dy=spread_ptr?8*spread_ptr->labelsize():300;
2056 #endif
2057       Fl_Group::current(0);
2058       w=new Fl_Window(dx,dy);
2059       fcn=new Fl_Input(dx/2,2,dx/2-4,dy/lignes-4,gettext("Expression"));
2060       fcn->value("(x+2)/(x+1)");
2061       fcn->tooltip(gettext("Expression of u_(n+1) in terms of a variable=u_n, e.g. 1/2*(x+2/x)\nOr expression of u_(n+k+1) in terms of a list of variables=[u_n,...,u_(n+k)], e.g. x+y"));
2062       varname=new Fl_Input(dx/2,2+dy/lignes,dx/2-4,dy/lignes-4,gettext("Variable(s)"));
2063       varname->value("x");
2064       varname->tooltip(gettext("Independant variable name representing u_n, e.g. x\nOr list of independant variables representing u_n,...,u_(n+k), e.g. [x,y]"));
2065       u0name = new Fl_Input(0,2+2*dy/lignes,dx/8,dy/lignes-4);
2066       u0name->value("u0");
2067       u0name->tooltip(gettext("Name of the initial value of un"));
2068       u0 = new Fl_Input(dx/6,2+2*dy/lignes,dx/3,dy/lignes-4,gettext("="));
2069       u0->value("1.0");
2070       u0->tooltip(gettext("Initial value, e.g. 1.0\nOr list of initial values, e.g. [1.0,1.0]"));
2071       xmin = new Fl_Value_Input(dx/2+dx/8,2+2*dy/lignes,dx/8-2,dy/lignes-4,gettext("x-"));
2072       xmin->value(gnuplot_xmin);
2073       xmin->tooltip(gettext("Minimal value for the function graph"));
2074       xmax = new Fl_Value_Input(dx/2+3*dx/8,2+2*dy/lignes,dx/8-2,dy/lignes-4,gettext("x+"));
2075       xmax->value(gnuplot_xmax);
2076       xmax->tooltip(gettext("Maximal value for the function graph"));
2077       target = new Fl_Input(dx/2,2+3*dy/lignes,dx/2-2,dy/lignes-4,gettext("Target column"));
2078       target->tooltip("Name of the column that will be overwritten by the table of the sequence");
2079       nterms = new Fl_Value_Input(dx/2,2+3*dy/lignes,dx/2-2,dy/lignes-4,gettext("Number of terms"));
2080       nterms->value(10);
2081       nterms->step(1);
2082       button0 = new Fl_Return_Button(2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
2083       button0->shortcut(0xff0d);
2084       button0->label(gettext("OK"));
2085       button1 = new Fl_Button(dx/2+2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
2086       button1->shortcut(0xff1b);
2087       button1->label(gettext("Cancel"));
2088       w->end();
2089       change_group_fontsize(w,spread_ptr?spread_ptr->labelsize():14);
2090       w->resizable(w);
2091     }
2092     Flv_Table_Gen * tbl=dynamic_cast<Flv_Table_Gen *>(spread_ptr);
2093     if (tbl){
2094       target->show();
2095       target->value(coltocolname(tbl->col()).c_str());
2096       nterms->hide();
2097       u0name->hide();
2098       u0->label("u0");
2099     }
2100     else {
2101       target->hide();
2102       nterms->show();
2103       u0name->show();
2104       u0->label("=");
2105     }
2106     w->label(title.c_str());
2107     int r=-1;
2108     w->set_modal();
2109     w->show();
2110     autosave_disabled=true;
2111     w->hotspot(w);
2112     Fl::focus(fcn);
2113     for (;;) {
2114       Fl_Widget *o = Fl::readqueue();
2115       if (!o) Fl::wait();
2116       else {
2117 	if (o == button0) {r = 0; break;}
2118 	if (o == button1) {r = 1; break;}
2119 	if (o == w) { r=1; break; }
2120       }
2121     }
2122     autosave_disabled=false;
2123     w->hide();
2124     if (!r){
2125       if (tbl){
2126 	int r;
2127 	if (!alphaposcell(target->value(),r)){
2128 	  fl_alert("%s","Invalid column");
2129 	  return false;
2130 	}
2131 	tbl->col(r);
2132 	tbl->row(1);
2133 	if (Tableur_Group * par=dynamic_cast<Tableur_Group *> (tbl->parent())){
2134 	  par->disposition=3;
2135 	  par->resize2();
2136 	}
2137       }
2138       gen cell;
2139       if (has_cell(fcn->value(),cell,context0)){
2140 	fl_alert("%s",(gettext("Expression contains a cell name ")+cell.print()).c_str());
2141 	return false;
2142       }
2143       if (gen(u0->value(),context0).type==_VECT){
2144 	fl_alert("%s",(string(gettext("Invalid list initial value "))+u0->value()).c_str());
2145 	return false;
2146       }
2147       if (Figure * fig = dynamic_cast<Figure *>(spread_ptr)){
2148 	fig->geo->window_xmin=xmin->value();
2149 	fig->geo->window_xmax=xmax->value();
2150 	fig->geo->orthonormalize();
2151       }
2152       u0param="assume("+string(u0name->value())+string("=[")+u0->value()+string(",")+print_DOUBLE_(xmin->value())+string(",")+print_DOUBLE_(xmax->value())+string("])");
2153       arg=fcn->value()+string(",")+varname->value();
2154       string u0s=tbl?u0->value():u0name->value();
2155       if (plot)
2156 	arg += string("=[")+u0s+string(",")+print_DOUBLE_(xmin->value())+string(",")+print_DOUBLE_(xmax->value())+string("],")+print_DOUBLE_(nterms->value());
2157       else
2158 	arg += string(",[")+u0s+string(",")+print_DOUBLE_(xmin->value())+string(",")+print_DOUBLE_(xmax->value())+string("]");
2159       return true;
2160     }
2161     return false;
2162   }
2163 
cb_Tableur_ranm(Fl_Menu_ * m,void *)2164    void cb_Tableur_ranm(Fl_Menu_* m , void*) {
2165     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2166     if (!spread_ptr) return;
2167     const giac::context * contextptr = get_context(spread_ptr);
2168     gen g;
2169     bool intg,once;
2170     double xmin,xmax;
2171     if (spread_ptr && random_dialog(spread_ptr,g,xmin,xmax,intg,once)){
2172       int r,c;
2173       string formulas;
2174       if (!once)
2175 	formulas="=";
2176       if (intg)
2177 	formulas+="floor(";
2178       formulas += "rand(";
2179       formulas += print_DOUBLE_(xmin);
2180       formulas += ",";
2181       formulas += print_DOUBLE_(intg?xmax+1:xmax);
2182       formulas += ")";
2183       if (intg)
2184 	formulas+=")";
2185       if (iscell(g,c,r,contextptr) ){
2186 	if (r>=spread_ptr->rows()||c>=spread_ptr->cols())
2187 	  spread_ptr->resizesheet(max(r+1,spread_ptr->rows()),max(c+1,spread_ptr->cols()));
2188 	// cerr << g << " " << r << " " << c << '\n';
2189 	spread_ptr->row(r);
2190 	spread_ptr->col(c);
2191 	spread_ptr->select_start_row(r);
2192 	spread_ptr->select_start_col(c);
2193 	if (spread_ptr->input){
2194 	  spread_ptr->input->value(formulas.c_str());
2195 	  spread_ptr->input->do_callback();
2196 	}
2197       } // end if iscell(g,r,c)
2198       if (!g.is_symb_of_sommet(at_interval))
2199 	return;
2200       gen & f=g._SYMBptr->feuille;
2201       if (f.type!=_VECT || f._VECTptr->size()!=2)
2202 	return;
2203       int r1,r2,c1,c2;
2204       if (!iscell(f._VECTptr->front(),c1,r1,contextptr) || !iscell(f._VECTptr->back(),c2,r2,contextptr))
2205 	return;
2206       if (r1>r2)
2207 	giac::swapint(r1,r2);
2208       r2=min(r2+1,spread_ptr->rows());
2209       r1=max(r1,0);
2210       if (c1>c2)
2211 	giac::swapint(c1,c2);
2212       c2=min(c2+1,spread_ptr->cols());
2213       c1=max(c1,0);
2214       gen formula(formulas,contextptr);
2215       for (int i=r1;i<r2;++i){
2216 	vecteur & v=*spread_ptr->m[i]._VECTptr;
2217 	for (int j=c1;j<c2;++j){
2218 	  v[j]=makevecteur((once?eval(formula,1,0):formula),0,2);
2219 	}
2220       }
2221       spread_ptr->spread_eval_interrupt();
2222       spread_ptr->redraw();
2223     }
2224   }
2225 
cb_Tableur_Tableseq(Fl_Menu_ * m,void *)2226    void cb_Tableur_Tableseq(Fl_Menu_* m , void*) {
2227     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2228     if (!spread_ptr) return;
2229     string arg,u0param;
2230     if (spread_ptr && tableseq_dialog(spread_ptr,arg,false,gettext("Table of value of a recurrent sequence"),u0param)){
2231       arg="tableseq("+arg+")";
2232       spread_ptr->input->value("");
2233       tableur_insert_replace(spread_ptr,arg);
2234       Tableur_Group * gr = dynamic_cast<Tableur_Group *>(spread_ptr->parent());
2235       if (gr && !(gr->disposition & 2) && !spread_ptr->graph2d->window()->visible()){
2236 	gr->disposition |= 2;
2237 	gr->resize2();
2238       }
2239       spread_ptr->input->do_callback();
2240       // browser_help(gen("tableseq"),language(get_context(spread_ptr)));
2241     }
2242   }
2243 
set_graphic_dialog(const string & title,const string & aide,gen & in,gen & out,bool show_class,bool & absolu,bool & transpose,double & degree)2244   int Flv_Table_Gen::set_graphic_dialog(const string & title,const string & aide,gen & in, gen & out,bool show_class,bool & absolu,bool & transpose,double & degree){
2245     const giac::context * contextptr = get_context(this);
2246     static Fl_Window * w = 0;
2247     static Fl_Output * help=0;
2248     static Fl_Input * i1=0, * i2=0; // Cells to analyse and cell output
2249     static Fl_Value_Input * v1=0, *v2=0,*v3=0; // Class_min/size, poly degree
2250     static Fl_Return_Button * button0 = 0 ;
2251     static Fl_Button * button1 =0;
2252     static Fl_Check_Button* c1=0,*c2=0,*c3=0;
2253     int dx=(2*this->w())/3,dy=(2*h())/3;
2254     if (dy<200)
2255       dy=200;
2256     if (dy>6*labelsize())
2257       dy=6*labelsize();
2258     if (dx<200)
2259       dx=200;
2260     if (!w){
2261       Fl_Group::current(0);
2262       w=new Fl_Window(dx,dy);
2263       int lignes=4;
2264       help = new Fl_Output(dx/2,2,0,0,"");
2265       help->align(FL_ALIGN_BOTTOM);
2266       i1=new Fl_Input(dx/4,2+dy/lignes,dx/4-2,dy/lignes-4,gettext("cells input"));
2267       i1->tooltip(gettext("Zone over which the function will be applied, e.g. A1..B7 or A1..B7,D,E"));
2268       i2=new Fl_Input((3*dx)/4,2+dy/lignes,dx/4-2,dy/lignes-4,gettext("target cell"));
2269       i2->tooltip(gettext("Target cell(s) will be filled by the formula, e.g. A8"));
2270       v1=new Fl_Value_Input(dx/4,2+2*dy/lignes,dx/4-2,dy/lignes-4,gettext("class min"));
2271       v1->tooltip(gettext("Minimal value of classes for histogramsl, e.g. -10"));
2272       v2=new Fl_Value_Input((3*dx)/4,2+2*dy/lignes,dx/4-2,dy/lignes-4,gettext("class size"));
2273       v2->tooltip(gettext("Size of a class for histograms, e.g. 2"));
2274       c1=new Fl_Check_Button(0, 2+2*dy/lignes,dx/8,dy/lignes-4,gettext("value"));
2275       c1->tooltip(gettext("Use submatrix by reference (dynamic) or by value (static)"));
2276       c1->down_box(FL_DOWN_BOX);
2277       c2=new Fl_Check_Button(dx/4, 2+2*dy/lignes,dx/8,dy/lignes-4,gettext("lines"));
2278       c2->tooltip(gettext("Use line or columns"));
2279       c2->down_box(FL_DOWN_BOX);
2280       c3=new Fl_Check_Button(dx/2, 2+2*dy/lignes,dx/8,dy/lignes-4,gettext("outside"));
2281       c3->tooltip(gettext("Sheet graph or standalone graph"));
2282       c3->down_box(FL_DOWN_BOX);
2283       v3=new Fl_Value_Input(3*dx/4+dx/8, 2+2*dy/lignes,dx/8,dy/lignes-4,gettext("degree"));
2284       v3->tooltip(gettext("Degree of the polynomial regression"));
2285       button0 = new Fl_Return_Button(2,2+(3*dy/lignes),dx/2-4,dy/lignes-4);
2286       button0->shortcut(0xff0d);
2287       button0->label(gettext("OK"));
2288       button1 = new Fl_Button(dx/2+2,2+(3*dy)/lignes,dx/2-4,dy/lignes-4);
2289       button1->shortcut(0xff1b);
2290       button1->label(gettext("Cancel"));
2291       w->end();
2292       w->resizable(w);
2293     }
2294     help->label(aide.c_str());
2295     w->label(title.c_str());
2296     change_group_fontsize(w,labelsize());
2297     /*
2298       printcell_current_row=row()+1;
2299       printcell_current_col=select_start_col();
2300       string s=printcell(makevecteur(makevecteur(0),makevecteur(0)));
2301       i2->value(s.c_str()); // removed so that the user MUST specify target
2302     */
2303     if (strlen(_goto->value()))
2304       i1->value(_goto->value());
2305     if (show_class){
2306       c3->value(false);
2307       c3->hide();
2308     }
2309     else
2310       c3->show();
2311     static string i2s;
2312     i2s=next_cell(i1->value(),this);
2313     i2->value(i2s.c_str());
2314     v1->value(class_minimum);
2315     v2->value(class_size);
2316     v3->value(degree);
2317     if (show_class){
2318       v1->show(); v2->show(); c1->hide(); c2->hide(); v3->hide();
2319     }
2320     else {
2321       v1->hide(); v2->hide(); c1->show();  c2->show();
2322       if (degree){
2323 	v3->label(degree==1?"y1":"degree");
2324 	v3->show();
2325       }
2326       else
2327 	v3->hide();
2328     }
2329     int r=-1;
2330     for (;;){
2331       w->set_modal();
2332       w->show();
2333       autosave_disabled=true;
2334       w->hotspot(w);
2335       Fl::focus(i1);
2336       for (;;) {
2337 	Fl_Widget *o = Fl::readqueue();
2338 	if (!o) Fl::wait();
2339 	else {
2340 	  if (o == button0) {r = 0; break;}
2341 	  if (o == button1) {r = 1; break;}
2342 	  if (o==c3){ if (c3->value()) i2->deactivate(); else i2->activate();}
2343 	  if (o == w) { r=1; break; }
2344 	}
2345       }
2346       autosave_disabled=false;
2347       w->hide();
2348       if (r)
2349 	break;
2350       // r=0, not cancelled
2351       degree=int(v3->value());
2352       absolu=c1->value();
2353       transpose=c2->value();
2354       class_minimum=v1->value();
2355       class_size=v2->value();
2356       const char * ch =i1->value();
2357       string s;
2358       int l=strlen(ch);
2359       for (int i=0;i<l;++i,++ch){
2360 	if (*ch==':')
2361 	  s += "..";
2362 	else
2363 	  s+=*ch;
2364       }
2365       try {
2366 	in=gen(s,contextptr);
2367 	out=(c3->value() || !strlen(i2->value()))?undef:gen(i2->value(),contextptr);
2368 	Tableur_Group * gr = dynamic_cast<Tableur_Group *>(parent());
2369 	if (!is_undef(out) && gr && !(gr->disposition & 2) ){
2370 	  gr->disposition |= 2;
2371 	  gr->resize2();
2372 	}
2373       }
2374       catch (std::runtime_error & e){
2375 	fl_message("%s",(gettext("Syntax error")+string(e.what())).c_str());
2376 	continue;
2377       }
2378       break;
2379     } // end endless for(;;) loop
2380     return r;
2381   }
2382 
interval2deuxpoints(const gen & g)2383   gen interval2deuxpoints(const gen & g){
2384     return g.is_symb_of_sommet(at_interval)?symbolic(at_deuxpoints,g._SYMBptr->feuille):g;
2385   }
2386 
set_graphic(const gen & function,const std::string & aide)2387   void Flv_Table_Gen::set_graphic(const gen & function,const std::string & aide){
2388     if (function.type!=_FUNC)
2389       return;
2390     gen in,out;
2391     bool absolu=false,transpose;
2392     string fs=function.print(contextptr);
2393     double deg=0;
2394     bool polyreg=(fs=="'polynomial_regression_plot'");
2395     bool logisreg=(fs=="'logistic_regression_plot'");
2396     if (polyreg)
2397       deg=2;
2398     if (logisreg)
2399       deg=1;
2400     int r=set_graphic_dialog(fs,aide,in,out,fs=="'histogram'",absolu,transpose,deg);
2401     if (r==0){
2402       gen tmp;
2403       int r1,r2,res,R,C;
2404       vector<int> vc;
2405       matrice mselect;
2406       bool absolu2=false;
2407       if ( (res=iscell_range(in,m,mselect,this,r1,r2,vc,absolu2)) ){
2408 	bool inside=iscell(out,C,R,contextptr);
2409 	// If vc.size()!=#cols mselect colmuns are non-contiguous,
2410 	// use mselect else use matrix(r2-r1+1,vc.size(),g)
2411 	if (absolu || mselect.front()._VECTptr->size()!=vc.size() || (inside?absolu2:name.type!=_IDNT) ){
2412 	  tmp=extractmatricefromsheet(mselect);
2413 	  if (transpose)
2414 	    tmp=_tran(tmp,contextptr);
2415 	}
2416 	else {
2417 	  if (inside){
2418 	    in=apply(in,interval2deuxpoints);
2419 	    tmp=logisreg?in:symbolic(at_matrix,makevecteur(r2-r1,vc.size(),in));
2420 	  }
2421 	  else {
2422 	    vecteur vcg;
2423 	    vector_int2vecteur(vc,vcg);
2424 	    in=gen(makevecteur(symb_interval(r1,r2-1),vcg),_SEQ__VECT);
2425 	    tmp=symbolic(at_at,gen(makevecteur(name,in),_SEQ__VECT));
2426 	  }
2427 	  if (transpose)
2428 	    tmp=symbolic(at_tran,tmp);
2429 	}
2430 	if (polyreg)
2431 	  tmp=gen(makevecteur(tmp,deg),_SEQ__VECT);
2432 	if (logisreg)
2433 	  tmp=gen(makevecteur(tmp,1,deg),_SEQ__VECT);
2434 	tmp=symbolic(*function._FUNCptr,tmp);
2435 	if (inside){
2436 	  tmp.change_subtype(_SPREAD__SYMB);
2437 	  row(R);
2438 	  col(C);
2439 	  input->value(tmp.print(contextptr).c_str());
2440 	  // input->set_g(tmp);
2441 	  input->do_callback();
2442 	}
2443 	else {
2444 	  int pos;
2445 	  History_Pack * hp=get_history_pack(this,pos);
2446 	  if (hp){
2447 	    hp->add_entry(pos+1);
2448 	    hp->set_gen_value(pos+1,tmp,true);
2449 	  }
2450 	}
2451       }
2452     }
2453   }
2454 
cb_Tableur_SetRows(Fl_Menu_ * m,void *)2455    void cb_Tableur_SetRows(Fl_Menu_* m , void*) {
2456     Flv_Table_Gen * tg=find_table_brother(m);
2457     if (!tg) return;
2458     const char * ch=fl_input(gettext("New row number"),print_INT_(tg->rows()).c_str());
2459     if (ch){
2460       int i=atoi(ch);
2461       if (i<tg->rows()){
2462 	int j=fl_ask("%s",gettext("Really delete rows?"));
2463 	if (!j)
2464 	  return;
2465       }
2466       if (i>0 && double(i)*tg->cols()<7e4)
2467 	tg->resizesheet(i,tg->cols());
2468     }
2469   }
2470 
cb_Tableur_SetCols(Fl_Menu_ * m,void *)2471    void cb_Tableur_SetCols(Fl_Menu_* m , void*) {
2472     Flv_Table_Gen * tg=find_table_brother(m);
2473     if (!tg) return;
2474     const char * ch=fl_input(gettext("New col number"),print_INT_(tg->cols()).c_str());
2475     if (ch){
2476       int i=atoi(ch);
2477       if (i<tg->cols()){
2478 	int j=fl_ask("%s",gettext("Really delete columns?"));
2479 	if (!j)
2480 	  return;
2481       }
2482       if (i>0 && double(i)*tg->rows()<7e4){
2483 	tg->resizesheet(tg->rows(),i);
2484       }
2485     }
2486   }
2487 
cb_Tableur_Histogram(Fl_Menu_ * m,void *)2488    void cb_Tableur_Histogram(Fl_Menu_* m , void*) {
2489     Flv_Table_Gen * tg=find_table_brother(m);
2490     if (!tg) return;
2491     const giac::context * contextptr = get_context(tg);
2492     tg->set_graphic(gen("histogram",contextptr),gettext("Histogram 1 or 2 columns: data or data/eff"));
2493   }
2494 
cb_Tableur_Classes(Fl_Menu_ * m,void *)2495    void cb_Tableur_Classes(Fl_Menu_* m , void*) {
2496     Flv_Table_Gen * tg=find_table_brother(m);
2497     if (!tg) return;
2498     const giac::context * contextptr = get_context(tg);
2499     gen in,out;
2500     bool absolu,transpose; // always true for histograms
2501     double deg=0;
2502     int r=tg->set_graphic_dialog("classes",gettext("Make classes from column data or data/eff into two adjacent columns"),in,out,true,absolu,transpose,deg);
2503     if (r==0){
2504       gen tmp;
2505       int r1,r2,R,C;
2506       vector<int> vc;
2507       matrice mselect;
2508       if ( (iscell_range(in,tg->m,mselect,tg,r1,r2,vc,absolu)==1) && iscell(out,C,R,contextptr) ){
2509 	matrice g;
2510 	try {
2511 	  tg->select_start_row(r1); tg->row(r2-1);
2512 	  tg->select_start_col(vc.front()); tg->col(vc.back());
2513 	  tg->copy();
2514 	  matrice tmp=extractmatricefromsheet(tg->selected);
2515 	  if (transpose)
2516 	    tmp=mtran(tmp);
2517 	  g=effectifs(tmp,class_minimum,class_size,get_context(tg));
2518 	} catch (std::runtime_error & e){
2519 	  return;
2520 	}
2521 	tg->row(R); tg->col(C);
2522 	tg->paste(g);
2523       }
2524     }
2525   }
2526 
cb_Tableur_Boxwhisker(Fl_Menu_ * m,void *)2527    void cb_Tableur_Boxwhisker(Fl_Menu_* m , void*) {
2528     Flv_Table_Gen * tg=find_table_brother(m);
2529     if (!tg) return;
2530     const giac::context * contextptr = get_context(tg);
2531     tg->set_graphic(gen("boxwhisker",contextptr),gettext("One boxwhisker per column"));
2532   }
2533 
cb_Tableur_plotlist(Fl_Menu_ * m,void *)2534    void cb_Tableur_plotlist(Fl_Menu_* m , void*) {
2535     Flv_Table_Gen * tg=find_table_brother(m);
2536     if (!tg) return;
2537     const giac::context * contextptr = get_context(tg);
2538     tg->set_graphic(gen("plotlist",contextptr),gettext("Plotlist: One column (y) or two columns (x,y)"));
2539   }
2540 
cb_Tableur_camembert(Fl_Menu_ * m,void *)2541    void cb_Tableur_camembert(Fl_Menu_* m , void*) {
2542     Flv_Table_Gen * tg=find_table_brother(m);
2543     if (!tg) return;
2544     const giac::context * contextptr = get_context(tg);
2545     tg->set_graphic(gen("camembert",contextptr),gettext("Camembert: column 1: legends, column 2: data"));
2546   }
2547 
cb_Tableur_batons(Fl_Menu_ * m,void *)2548    void cb_Tableur_batons(Fl_Menu_* m , void*) {
2549     Flv_Table_Gen * tg=find_table_brother(m);
2550     if (!tg) return;
2551     const giac::context * contextptr = get_context(tg);
2552     tg->set_graphic(gen("bar_plot",contextptr),gettext("Bar_plot: column 1: legends, column 2: data"));
2553   }
2554 
cb_Tableur_Scatterplot(Fl_Menu_ * m,void *)2555    void cb_Tableur_Scatterplot(Fl_Menu_* m , void*) {
2556     Flv_Table_Gen * tg=find_table_brother(m);
2557     if (!tg) return;
2558     const giac::context * contextptr = get_context(tg);
2559     tg->set_graphic(gen("scatterplot",contextptr),gettext("Column 1: x, one scatterplot per remaining column"));
2560   }
2561 
cb_Tableur_Polygonplot(Fl_Menu_ * m,void *)2562    void cb_Tableur_Polygonplot(Fl_Menu_* m , void*) {
2563     Flv_Table_Gen * tg=find_table_brother(m);
2564     if (!tg) return;
2565     const giac::context * contextptr = get_context(tg);
2566     tg->set_graphic(gen("polygonplot",contextptr),gettext("Column 1: x, one polygonplot per remaining column"));
2567   }
2568 
cb_Tableur_Polygonscatterplot(Fl_Menu_ * m,void *)2569    void cb_Tableur_Polygonscatterplot(Fl_Menu_* m , void*) {
2570     Flv_Table_Gen * tg=find_table_brother(m);
2571     if (!tg) return;
2572     const giac::context * contextptr = get_context(tg);
2573     tg->set_graphic(gen("polygonscatterplot",contextptr),gettext("Column 1: x, one polygon line per remaining column"));
2574   }
2575 
cb_Tableur_linear_regression_plot(Fl_Menu_ * m,void *)2576    void cb_Tableur_linear_regression_plot(Fl_Menu_* m , void*) {
2577     Flv_Table_Gen * tg=find_table_brother(m);
2578     if (!tg) return;
2579     const giac::context * contextptr = get_context(tg);
2580     tg->set_graphic(gen("linear_regression_plot",contextptr),gettext("Linear regression: column 1: x, column 2: y"));
2581   }
2582 
cb_Tableur_power_regression_plot(Fl_Menu_ * m,void *)2583    void cb_Tableur_power_regression_plot(Fl_Menu_* m , void*) {
2584     Flv_Table_Gen * tg=find_table_brother(m);
2585     if (!tg) return;
2586     const giac::context * contextptr = get_context(tg);
2587     tg->set_graphic(gen("power_regression_plot",contextptr),gettext("Power regression: Column 1: x, column 2: y"));
2588   }
2589 
cb_Tableur_logarithmic_regression_plot(Fl_Menu_ * m,void *)2590    void cb_Tableur_logarithmic_regression_plot(Fl_Menu_* m , void*) {
2591     Flv_Table_Gen * tg=find_table_brother(m);
2592     if (!tg) return;
2593     const giac::context * contextptr = get_context(tg);
2594     tg->set_graphic(gen("logarithmic_regression_plot",contextptr),gettext("Log regression: Column 1: x, column 2: y"));
2595   }
2596 
cb_Tableur_exponential_regression_plot(Fl_Menu_ * m,void *)2597    void cb_Tableur_exponential_regression_plot(Fl_Menu_* m , void*) {
2598     Flv_Table_Gen * tg=find_table_brother(m);
2599     if (!tg) return;
2600     const giac::context * contextptr = get_context(tg);
2601     tg->set_graphic(gen("exponential_regression_plot",contextptr),gettext("Exp regression: Column 1: x, column 2: y"));
2602   }
2603 
cb_Tableur_polynomial_regression_plot(Fl_Menu_ * m,void *)2604    void cb_Tableur_polynomial_regression_plot(Fl_Menu_* m , void*) {
2605     Flv_Table_Gen * tg=find_table_brother(m);
2606     if (!tg) return;
2607     const giac::context * contextptr = get_context(tg);
2608     tg->set_graphic(gen("polynomial_regression_plot",contextptr),gettext("Polynomial regression degree d: Column 1: x, column 2: y"));
2609   }
2610 
cb_Tableur_logistic_regression_plot(Fl_Menu_ * m,void *)2611    void cb_Tableur_logistic_regression_plot(Fl_Menu_* m , void*) {
2612     Flv_Table_Gen * tg=find_table_brother(m);
2613     if (!tg) return;
2614     const giac::context * contextptr = get_context(tg);
2615     tg->set_graphic(gen("logistic_regression_plot",contextptr),gettext("Logistic regression for y', with y(x=1)=y1"));
2616   }
2617 
find_sort_row(int c2,bool isrow,GIAC_CONTEXT)2618   int find_sort_row(int c2,bool isrow,GIAC_CONTEXT){
2619     int c;
2620     if (xcas_mode(contextptr))
2621       c=c2+1;
2622     else
2623       c=c2;
2624     string question=gettext("Sort with respect to ");
2625     if (isrow)
2626       question += gettext("row");
2627     else
2628       question += gettext("column");
2629     const char * chptr=fl_input("%s",print_INT_(c).c_str(),question.c_str());
2630     if (!chptr)
2631       return -1;
2632     string colonne(chptr);
2633     gen g(colonne,contextptr);
2634     if (xcas_mode(contextptr))
2635       g = g + minus_one;
2636     if (g.type!=_INT_ )
2637       return -1;
2638     return g.val;
2639   }
2640 
2641   // Global variable is used for sorting only.
2642   static Flv_Table_Gen * current_spread_ptr;
thesheetsort(const gen & a,const gen & b)2643   bool thesheetsort(const gen & a,const gen &b){
2644     const giac::context * contextptr = get_context(current_spread_ptr);
2645     gen a1=a[current_spread_ptr->sort_col][1].evalf_double(1,contextptr),a2=b[current_spread_ptr->sort_col][1].evalf_double(1,contextptr);
2646     if (a1.type!=_DOUBLE_ || a2.type!=_DOUBLE_)
2647       return a1.islesscomplexthan(a2);
2648     return a1._DOUBLE_val<a2._DOUBLE_val;
2649   }
2650 
sheetsort(Flv_Table_Gen * spread_ptr,bool row_sort,bool increasing)2651   void sheetsort(Flv_Table_Gen * spread_ptr,bool row_sort,bool increasing){
2652     const giac::context * contextptr = get_context(spread_ptr);
2653     current_spread_ptr=spread_ptr;
2654     if (spread_ptr->is_spreadsheet){
2655       int i=fl_ask("%s",gettext("Sorting is not compatible with some cell references. Sort anyway"),gettext("Yes"),gettext("No"));
2656       if (i!=1) return ;
2657     }
2658     int r1,r2,c1,c2;
2659     matrice m;
2660     if (row_sort){ // Transpose if sort w.r. to current row
2661       m=mtran(spread_ptr->m);
2662       r1=spread_ptr->col();
2663       r2=spread_ptr->push_col;
2664       c1=spread_ptr->row();
2665       c2=spread_ptr->push_row;
2666       int r=find_sort_row(c2,true,contextptr);
2667       if (r<0 || r>=spread_ptr->rows())
2668 	return;
2669       spread_ptr->sort_col=r;
2670     }
2671     else {
2672       m=spread_ptr->m;
2673       r1=spread_ptr->row();
2674       r2=spread_ptr->push_row;
2675       c1=spread_ptr->col();
2676       c2=spread_ptr->push_col;
2677       if (spread_ptr->is_spreadsheet){
2678 	int r,c;
2679 	string tmp=coltocolname(c2);
2680 	string question=gettext("Sort with respect to ");
2681 	if (row_sort)
2682 	  question += gettext("row");
2683 	else
2684 	  question += gettext("column");
2685 	const char * chptr=fl_input("%s",tmp.c_str(),question.c_str());
2686 	if (!chptr){
2687 	  return;
2688 	}
2689 	string therow=chptr;
2690 	therow +='1';
2691 	if (!iscell(gen(therow,contextptr),r,c,contextptr))
2692 	  return;
2693 	spread_ptr->sort_col=r;
2694       }
2695       else {
2696 	int c=find_sort_row(c2,false,contextptr);
2697 	if (c<0 || c>= spread_ptr->cols() )
2698 	  return;
2699 	spread_ptr->sort_col=c;
2700       }
2701     }
2702     if (r1==r2)
2703       return;
2704     if (r1>r2)
2705       giac::swapint(r1,r2);
2706     if (c1>c2)
2707       giac::swapint(c1,c2);
2708     // keep only rows r1->r2 and cols c1->c2
2709     m=mtran(matrice(m.begin()+r1,m.begin()+r2+1));
2710     m=mtran(matrice(m.begin()+c1,m.begin()+c2+1));
2711     // sort
2712     spread_ptr->sort_col -= c1;
2713     sort(m.begin(),m.end(),thesheetsort);
2714     if (!increasing)
2715       reverse(m.begin(),m.end());
2716     // put in the matrix
2717     if (row_sort){ // Back transpose
2718       m=mtran(m);
2719       spread_ptr->row(c1);
2720       spread_ptr->col(r1);
2721     }
2722     else {
2723       spread_ptr->row(r1);
2724       spread_ptr->col(c1);
2725     }
2726     spread_ptr->paste(m);
2727   }
2728 
cb_Tableur_Sort_Dec_Col(Fl_Menu_ * m,void *)2729    void cb_Tableur_Sort_Dec_Col(Fl_Menu_* m , void*) {
2730     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2731     if (!spread_ptr) return;
2732     sheetsort(spread_ptr,false,false);
2733     spread_ptr->spread_eval_interrupt();
2734     spread_ptr->redraw();
2735   }
2736 
cb_Tableur_Sort_Inc_Col(Fl_Menu_ * m,void *)2737    void cb_Tableur_Sort_Inc_Col(Fl_Menu_* m , void*) {
2738     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2739     if (!spread_ptr) return;
2740     sheetsort(spread_ptr,false,true);
2741     spread_ptr->spread_eval_interrupt();
2742     spread_ptr->redraw();
2743   }
2744 
cb_Tableur_Sort_Dec_Row(Fl_Menu_ * m,void *)2745    void cb_Tableur_Sort_Dec_Row(Fl_Menu_* m , void*) {
2746     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2747     if (!spread_ptr) return;
2748     sheetsort(spread_ptr,true,false);
2749     spread_ptr->spread_eval_interrupt();
2750     spread_ptr->redraw();
2751   }
2752 
cb_Tableur_Sort_Inc_Row(Fl_Menu_ * m,void *)2753    void cb_Tableur_Sort_Inc_Row(Fl_Menu_* m , void*) {
2754     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2755     if (!spread_ptr) return;
2756     sheetsort(spread_ptr,true,true);
2757     spread_ptr->spread_eval_interrupt();
2758     spread_ptr->redraw();
2759   }
2760 
cb_Tableur_Auto_Recompute(Fl_Menu_ * m,void *)2761    void cb_Tableur_Auto_Recompute(Fl_Menu_* m , void*) {
2762     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2763     if (!spread_ptr) return;
2764     spread_ptr->spreadsheet_recompute=1;
2765     spread_ptr->update_status();
2766   }
2767 
cb_Tableur_No_Recompute(Fl_Menu_ * m,void *)2768    void cb_Tableur_No_Recompute(Fl_Menu_* m , void*) {
2769     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2770     if (!spread_ptr) return;
2771     spread_ptr->spreadsheet_recompute=0;
2772     spread_ptr->update_status();
2773   }
2774 
cb_Tableur_Matrix_Fill(Fl_Menu_ * m,void *)2775    void cb_Tableur_Matrix_Fill(Fl_Menu_* m , void*) {
2776     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2777     if (!spread_ptr) return;
2778     spread_ptr->matrix_fill_cells=1;
2779     spread_ptr->update_status();
2780   }
2781 
cb_Tableur_No_Matrix_Fill(Fl_Menu_ * m,void *)2782    void cb_Tableur_No_Matrix_Fill(Fl_Menu_* m , void*) {
2783     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2784     if (!spread_ptr) return;
2785     spread_ptr->matrix_fill_cells=0;
2786     spread_ptr->update_status();
2787   }
2788 
cb_Tableur_Variable_Name(Fl_Menu_ * m,void *)2789    void cb_Tableur_Variable_Name(Fl_Menu_* m , void*) {
2790     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2791     if (!spread_ptr) return;
2792     spread_ptr->config();
2793   }
2794 
cb_Tableur_Spreadsheet_Mode(Fl_Menu_ * m,void *)2795    void cb_Tableur_Spreadsheet_Mode(Fl_Menu_* m , void*) {
2796     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2797     if (!spread_ptr) return;
2798     spread_ptr->is_spreadsheet=1;
2799     spread_ptr->update_status();
2800   }
2801 
cb_Tableur_Matrix_Mode(Fl_Menu_ * m,void *)2802    void cb_Tableur_Matrix_Mode(Fl_Menu_* m , void*) {
2803     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2804     if (!spread_ptr) return;
2805     spread_ptr->is_spreadsheet=0;
2806     spread_ptr->update_status();
2807   }
2808 
cb_Tableur_Normal_Matrix(Fl_Menu_ * m,void *)2809    void cb_Tableur_Normal_Matrix(Fl_Menu_* m , void*) {
2810     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2811     if (!spread_ptr) return;
2812     spread_ptr->matrix_symmetry=0;
2813     spread_ptr->update_status();
2814   }
2815 
cb_Tableur_Symmetric_Matrix(Fl_Menu_ * m,void *)2816    void cb_Tableur_Symmetric_Matrix(Fl_Menu_* m , void*) {
2817     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2818     if (!spread_ptr) return;
2819     if (spread_ptr->rows()!=spread_ptr->cols()){
2820       fl_message("%s",gettext("Make rows==cols first!"));
2821       return;
2822     }
2823     spread_ptr->is_spreadsheet=0;
2824     spread_ptr->matrix_symmetry=4;
2825     spread_ptr->update_status();
2826   }
2827 
cb_Tableur_AntiSymmetric_Matrix(Fl_Menu_ * m,void *)2828    void cb_Tableur_AntiSymmetric_Matrix(Fl_Menu_* m , void*) {
2829     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2830     if (!spread_ptr) return;
2831     if (spread_ptr->rows()!=spread_ptr->cols()){
2832       fl_message("%s",gettext("Make rows==cols first!"));
2833       return;
2834     }
2835     spread_ptr->is_spreadsheet=0;
2836     spread_ptr->matrix_symmetry=3;
2837     spread_ptr->update_status();
2838   }
2839 
cb_Tableur_Hermitian_Matrix(Fl_Menu_ * m,void *)2840    void cb_Tableur_Hermitian_Matrix(Fl_Menu_* m , void*) {
2841     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2842     if (!spread_ptr) return;
2843     if (spread_ptr->rows()!=spread_ptr->cols()){
2844       fl_message("%s",gettext("Make rows==cols first!"));
2845       return;
2846     }
2847     spread_ptr->is_spreadsheet=0;
2848     spread_ptr->matrix_symmetry=2;
2849     spread_ptr->update_status();
2850   }
2851 
cb_Tableur_AntiHermitian_Matrix(Fl_Menu_ * m,void *)2852    void cb_Tableur_AntiHermitian_Matrix(Fl_Menu_* m , void*) {
2853     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2854     if (!spread_ptr) return;
2855     if (spread_ptr->rows()!=spread_ptr->cols()){
2856       fl_message("%s",gettext("Make rows==cols first!"));
2857       return;
2858     }
2859     spread_ptr->is_spreadsheet=0;
2860     spread_ptr->matrix_symmetry=1;
2861     spread_ptr->update_status();
2862   }
2863 
cb_Tableur_Hide_Graph(Fl_Menu_ * m,void *)2864    void cb_Tableur_Hide_Graph(Fl_Menu_* m , void*) {
2865     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2866     if (!spread_ptr) return;
2867     Tableur_Group * tg=dynamic_cast<Tableur_Group *>(spread_ptr->parent());
2868     if (tg){
2869       if (tg->disposition & 0x2)
2870 	tg->save_dparam();
2871       tg->disposition=0;
2872       tg->resize2();
2873       tg->redraw();
2874     }
2875   }
2876 
cb_Tableur_Portrait(Fl_Menu_ * m,void *)2877    void cb_Tableur_Portrait(Fl_Menu_* m , void*) {
2878     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2879     if (!spread_ptr) return;
2880     Tableur_Group * tg=dynamic_cast<Tableur_Group *>(spread_ptr->parent());
2881     if (tg){
2882       tg->disposition=3;
2883       tg->resize2();
2884       tg->redraw();
2885     }
2886   }
2887 
cb_Tableur_Landscape(Fl_Menu_ * m,void *)2888    void cb_Tableur_Landscape(Fl_Menu_* m , void*) {
2889     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2890     if (!spread_ptr) return;
2891     Tableur_Group * tg=dynamic_cast<Tableur_Group *>(spread_ptr->parent());
2892     if (tg){
2893       tg->disposition=2;
2894       tg->resize2();
2895       tg->redraw();
2896     }
2897   }
2898 
cb_Tableur_Autoscale(Fl_Menu_ * m,void *)2899    void cb_Tableur_Autoscale(Fl_Menu_* m , void*) {
2900     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2901     if (!spread_ptr) return;
2902     Tableur_Group * tg=dynamic_cast<Tableur_Group *>(spread_ptr->parent());
2903     if (tg){
2904       tg->disposition |= 2;
2905       tg->resize2();
2906       tg->table->graph->autoscale();
2907       tg->redraw();
2908     }
2909   }
2910 
cb_Tableur_Cfg_Window(Fl_Menu_ * m,void *)2911    void cb_Tableur_Cfg_Window(Fl_Menu_* m , void*) {
2912     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2913     if (!spread_ptr) return;
2914     if (spread_ptr)
2915       spread_ptr->config();
2916   }
2917 
cb_Tableur_Undo(Fl_Menu_ * m,void *)2918    void cb_Tableur_Undo(Fl_Menu_* m , void*) {
2919     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2920     if (spread_ptr)
2921       spread_ptr->restore(-1);
2922   }
2923 
cb_Tableur_Redo(Fl_Menu_ * m,void *)2924    void cb_Tableur_Redo(Fl_Menu_* m , void*) {
2925     Flv_Table_Gen * spread_ptr=find_table_brother(m);
2926     if (spread_ptr)
2927       spread_ptr->restore(1);
2928   }
2929 
2930   Fl_Menu_Item Tableur_menu[] = {
2931     {gettext("Table"), 0,  0, 0, 64, 0, 0, 14, 56},
2932     {gettext("Save sheet as text"), 0,  (Fl_Callback*)cb_Tableur_Save, 0, 0, 0, 0, 14, 56},
2933     {gettext("Save as alternate filename"), 0,  (Fl_Callback*)cb_Tableur_Save_as, 0, 0, 0, 0, 14, 56},
2934     {gettext("Save as CSV"), 0,  (Fl_Callback*)cb_Tableur_Save_CSV, 0, 0, 0, 0, 14, 56},
2935     {gettext("Save as mathml"), 0,  (Fl_Callback*)cb_Tableur_Save_mathml, 0, 0, 0, 0, 14, 56},
2936     {gettext("Save selection to variable"), 0,  (Fl_Callback*)cb_Tableur_Save_var, 0, 0, 0, 0, 14, 56},
2937     {gettext("Insert"), 0,  (Fl_Callback*)cb_Tableur_Insert, 0, 0, 0, 0, 14, 56},
2938     {gettext("Insert CSV"), 0,  (Fl_Callback*)cb_Tableur_Insert_CSV, 0, 0, 0, 0, 14, 56},
2939     {gettext("Sheet configuration"), 0,  (Fl_Callback*)cb_Tableur_Variable_Name, 0, 0, 0, 0, 14, 56},
2940     {gettext("Print Export"), 0,  0, 0, 64, 0, 0, 14, 56},
2941     //    {gettext("latex preview"), 0,  (Fl_Callback*)cb_Tableur_LaTeX_Preview, 0, 0, 0, 0, 14, 56},
2942     //    {gettext("latex printer"), 0,  (Fl_Callback*)cb_Tableur_LaTeX_Print, 0, 0, 0, 0, 14, 56},
2943     {gettext("EPS PNG and preview"), 0,  (Fl_Callback*)cb_Tableur_Preview, 0, 0, 0, 0, 14, 56},
2944     {gettext("to printer"), 0,  (Fl_Callback*)cb_Tableur_Print, 0, 0, 0, 0, 14, 56},
2945     {0},
2946     {0},
2947     {gettext("Edit"), 0,  0, 0, 64, 0, 0, 14, 56},
2948     {gettext("Eval sheet"), 0xffc6,  (Fl_Callback *) cb_Tableur_Eval_Sheet, 0, 0, 0, 0, 14, 56},
2949     {gettext("Copy Cell"), 0,  (Fl_Callback *) cb_Tableur_Copy_Cell, 0, 0, 0, 0, 14, 56},
2950     {gettext("Paste"), 0,  (Fl_Callback *) cb_Paste, 0, 0, 0, 0, 14, 56},
2951     {gettext("Undo"), 0x4007a,  (Fl_Callback *) cb_Tableur_Undo, 0, 0, 0, 0, 14, 56},
2952     {gettext("Redo"), 0x40079,  (Fl_Callback *) cb_Tableur_Redo, 0, 0, 0, 0, 14, 56},
2953     {gettext("Configuration"), 0,  0, 0, 64, 0, 0, 14, 56},
2954     {gettext("Cfg window"), 0,  (Fl_Callback *) cb_Tableur_Cfg_Window, 0, 0, 0, 0, 14, 56},
2955     {gettext("Graph"), 0,  0, 0, 64, 0, 0, 14, 56},
2956     {gettext("Autoscale graph"), 0,  (Fl_Callback *) cb_Tableur_Autoscale, 0, 0, 0, 0, 14, 56},
2957     {gettext("Graph portrait"), 0,  (Fl_Callback *) cb_Tableur_Portrait, 0, 0, 0, 0, 14, 56},
2958     {gettext("Graph landscape"), 0,  (Fl_Callback *) cb_Tableur_Landscape, 0, 0, 0, 0, 14, 56},
2959     {gettext("Hide Graph"), 0,  (Fl_Callback *) cb_Tableur_Hide_Graph, 0, 0, 0, 0, 14, 56},
2960     {0}, // end graph
2961     {gettext("Format"), 0,  0, 0, 64, 0, 0, 14, 56},
2962     {gettext("Spreadsheet"), 0,  (Fl_Callback *) cb_Tableur_Spreadsheet_Mode, 0, 0, 0, 0, 14, 56},
2963     {gettext("Matrix"), 0,  (Fl_Callback *) cb_Tableur_Matrix_Mode, 0, 0, 0, 0, 14, 56},
2964     {gettext("Normal matrix"), 0,  (Fl_Callback *) cb_Tableur_Normal_Matrix, 0, 0, 0, 0, 14, 56},
2965     {gettext("Symmetric matrix"), 0,  (Fl_Callback *) cb_Tableur_Symmetric_Matrix, 0, 0, 0, 0, 14, 56},
2966     {gettext("AntiSymmetric matrix"), 0,  (Fl_Callback *) cb_Tableur_AntiSymmetric_Matrix, 0, 0, 0, 0, 14, 56},
2967     {gettext("Hermitian matrix"), 0,  (Fl_Callback *) cb_Tableur_Hermitian_Matrix, 0, 0, 0, 0, 14, 56},
2968     {gettext("AntiHermitian matrix"), 0,  (Fl_Callback *) cb_Tableur_AntiHermitian_Matrix, 0, 0, 0, 0, 14, 56},
2969     {0}, // end format
2970     {gettext("Set Rows Number"), 0,  (Fl_Callback *) cb_Tableur_SetRows, 0, 0, 0, 0, 14, 56},
2971     {gettext("Set Cols Number"), 0,  (Fl_Callback *) cb_Tableur_SetCols, 0, 0, 0, 0, 14, 56},
2972     {gettext("Move ->"), 0,  (Fl_Callback *) cb_Tableur_MoveRight, 0, 0, 0, 0, 14, 56},
2973     {gettext("Move down"), 0,  (Fl_Callback *) cb_Tableur_MoveDown, 0, 0, 0, 0, 14, 56},
2974     {gettext("Auto Recompute"), 0,  (Fl_Callback *) cb_Tableur_Auto_Recompute, 0, 0, 0, 0, 14, 56},
2975     {gettext("No Recompute"), 0,  (Fl_Callback *) cb_Tableur_No_Recompute, 0, 0, 0, 0, 14, 56},
2976     {gettext("Dispatch matrix to cells"), 0,  (Fl_Callback *) cb_Tableur_Matrix_Fill, 0, 0, 0, 0, 14, 56},
2977     {gettext("Keep matrix in one cell"), 0,  (Fl_Callback *) cb_Tableur_No_Matrix_Fill, 0, 0, 0, 0, 14, 56},
2978     {0}, // end Configuration
2979     {gettext("Fill"), 0,  0, 0, 64, 0, 0, 14, 56},
2980     {gettext("Copy right"), 0x40072,  (Fl_Callback *) cb_Tableur_Copy_Right, 0, 0, 0, 0, 14, 56},
2981     {gettext("Copy down"), 0x40064,  (Fl_Callback *) cb_Tableur_Copy_Down, 0, 0, 0, 0, 14, 56},
2982     {gettext("Fill selection with pushed cell"), 0,  (Fl_Callback *) cb_Tableur_FillSelection, 0, 0, 0, 0, 14, 56},
2983     {gettext("Fill selection with 0"), 0,  (Fl_Callback *) cb_Tableur_Fill0, 0, 0, 0, 0, 14, 56},
2984     {gettext("Fill sheet with 0"), 0,  (Fl_Callback *) cb_Tableur_Del, 0, 0, 0, 0, 14, 56},
2985     {0},
2986     {gettext("Add or delete"), 0,  0, 0, 64, 0, 0, 14, 56},
2987     {gettext("Insert Row"), 0,  (Fl_Callback *) cb_Tableur_InsRow, 0, 0, 0, 0, 14, 56},
2988     {gettext("Row+ at end"), 0,  (Fl_Callback *) cb_Tableur_InsRow_End, 0, 0, 0, 0, 14, 56},
2989     {gettext("Insert Col"), 0,  (Fl_Callback *) cb_Tableur_InsCol, 0, 0, 0, 0, 14, 56},
2990     {gettext("Col+ at end"), 0,  (Fl_Callback *) cb_Tableur_InsCol_End, 0, 0, 0, 0, 14, 56},
2991     {gettext("Erase current row"), 0,  (Fl_Callback *) cb_Tableur_DelRow, 0, 0, 0, 0, 14, 56},
2992     {gettext("Erase selection rows"), 0,  (Fl_Callback *) cb_Tableur_DelRows, 0, 0, 0, 0, 14, 56},
2993     {gettext("Erase current col"), 0,  (Fl_Callback *) cb_Tableur_DelCol, 0, 0, 0, 0, 14, 56},
2994     {gettext("Erase selection cols"), 0,  (Fl_Callback *) cb_Tableur_DelCols, 0, 0, 0, 0, 14, 56},
2995     {0},
2996     {gettext("Sort"), 0,  0, 0, 64, 0, 0, 14, 56},
2997     {gettext("Inc col"), 0,  (Fl_Callback *) cb_Tableur_Sort_Inc_Col, 0, 0, 0, 0, 14, 56},
2998     {gettext("Dec col"), 0,  (Fl_Callback *) cb_Tableur_Sort_Dec_Col, 0, 0, 0, 0, 14, 56},
2999     {gettext("Inc row"), 0,  (Fl_Callback *) cb_Tableur_Sort_Inc_Row, 0, 0, 0, 0, 14, 56},
3000     {gettext("Dec row"), 0,  (Fl_Callback *) cb_Tableur_Sort_Dec_Row, 0, 0, 0, 0, 14, 56},
3001     {0},
3002     {gettext("Col larger"), 0,  (Fl_Callback *) cb_Tableur_Col_Larger, 0, 0, 0, 0, 14, 56},
3003     {gettext("Col smaller"), 0,  (Fl_Callback *) cb_Tableur_Col_Smaller, 0, 0, 0, 0, 14, 56},
3004 #ifndef IPAQ // on ipaq put Stat inside Edit
3005     {0}, // end Edit
3006 #endif
3007     {gettext("Maths"), 0,  0, 0, 64, 0, 0, 14, 56},
3008     {gettext("Function"), 0,  (Fl_Callback *) cb_Tableur_Tablefunc, 0, 0, 0, 0, 14, 56},
3009     {gettext("Random values"), 0,  (Fl_Callback *) cb_Tableur_ranm, 0, 0, 0, 0, 14, 56},
3010     {gettext("Sequences"), 0,  0, 0, 64, 0, 0, 14, 56},
3011     {gettext("Recurrent sequence"), 0,  (Fl_Callback *) cb_Tableur_Tableseq, 0, 0, 0, 0, 14, 56},
3012     {gettext("Bar plot"), 0,  (Fl_Callback *) cb_Tableur_batons, 0, 0, 0, 0, 14, 56},
3013     {gettext("plotlist"), 0,  (Fl_Callback *) cb_Tableur_plotlist, 0, 0, 0, 0, 14, 56},
3014     {gettext("Polygonscatterplot"), 0,  (Fl_Callback *) cb_Tableur_Polygonscatterplot, 0, 0, 0, 0, 14, 56},
3015     {gettext("Scatterplot"), 0,  (Fl_Callback *) cb_Tableur_Scatterplot, 0, 0, 0, 0, 14, 56},
3016     {gettext("Polygonplot"), 0,  (Fl_Callback *) cb_Tableur_Polygonplot, 0, 0, 0, 0, 14, 56},
3017     {0},
3018     {gettext("1-d stats"), 0,  0, 0, 64, 0, 0, 14, 56},
3019     {gettext("camembert"), 0,  (Fl_Callback *) cb_Tableur_camembert, 0, 0, 0, 0, 14, 56},
3020     {gettext("Bar plot"), 0,  (Fl_Callback *) cb_Tableur_batons, 0, 0, 0, 0, 14, 56},
3021     {gettext("plotlist"), 0,  (Fl_Callback *) cb_Tableur_plotlist, 0, 0, 0, 0, 14, 56},
3022     {gettext("Boxwhisker"), 0,  (Fl_Callback *) cb_Tableur_Boxwhisker, 0, 0, 0, 0, 14, 56},
3023     {gettext("Classes (data or data,eff)"), 0,  (Fl_Callback *) cb_Tableur_Classes, 0, 0, 0, 0, 14, 56},
3024     {gettext("Histogram (interval,eff)"), 0,  (Fl_Callback *) cb_Tableur_Histogram, 0, 0, 0, 0, 14, 56},
3025     {0},
3026     {gettext("2-d stats"), 0,  0, 0, 64, 0, 0, 14, 56},
3027     {gettext("Polygonscatterplot"), 0,  (Fl_Callback *) cb_Tableur_Polygonscatterplot, 0, 0, 0, 0, 14, 56},
3028     {gettext("Scatterplot"), 0,  (Fl_Callback *) cb_Tableur_Scatterplot, 0, 0, 0, 0, 14, 56},
3029     {gettext("Polygonplot"), 0,  (Fl_Callback *) cb_Tableur_Polygonplot, 0, 0, 0, 0, 14, 56},
3030     {0}, // end 2-d
3031     {gettext("Regressions"), 0,  0, 0, 64, 0, 0, 14, 56},
3032     {gettext("Linear"), 0,  (Fl_Callback *) cb_Tableur_linear_regression_plot, 0, 0, 0, 0, 14, 56},
3033     {gettext("Polynomial"), 0,  (Fl_Callback *) cb_Tableur_polynomial_regression_plot, 0, 0, 0, 0, 14, 56},
3034     {gettext("Exponential"), 0,  (Fl_Callback *) cb_Tableur_exponential_regression_plot, 0, 0, 0, 0, 14, 56},
3035     {gettext("Logarithmic"), 0,  (Fl_Callback *) cb_Tableur_logarithmic_regression_plot, 0, 0, 0, 0, 14, 56},
3036     {gettext("Power"), 0,  (Fl_Callback *) cb_Tableur_power_regression_plot, 0, 0, 0, 0, 14, 56},
3037     {gettext("Logistic"), 0,  (Fl_Callback *) cb_Tableur_logistic_regression_plot, 0, 0, 0, 0, 14, 56},
3038     {0}, // end regressions
3039     {0}, // end Statistics
3040 #ifdef IPAQ
3041     {0}, // end Edit
3042 #endif
3043     {0} // end menu
3044   };
3045 
Tableur_callback(Flv_Table_Gen * l,void *)3046   void Tableur_callback(Flv_Table_Gen *l, void * ){
3047     l->header_event=l->why_event();
3048     // FLVE_TITLE_CLICKED, FLVE_ROW_HEADER_CLICKED, FLVE_COL_HEADER_CLICKED
3049     // FLVE_CLICKED
3050     if (l->header_event==FLVE_TITLE_CLICKED && l->last_event==FL_PUSH){
3051       if (l->computing)
3052 	kill_thread(true,l->contextptr);
3053       else
3054 	l->config();
3055       return;
3056     }
3057     /*
3058        if (!l->editing && l->header_event==FLVE_CLICKED && l->clicks()>1 && l->row()==l->select_start_row() && l->select_start_col()==l->col()){
3059       // double-click, begin copy cell to area
3060       l->click_fill=true;
3061       set_cursor(l,FL_CURSOR_HAND);
3062     }
3063     */
3064     if (l->header_event==FLVE_ROW_HEADER_CLICKED && l->rows()){
3065       if (l->last_event!=FL_PUSH)
3066 	l->row(l->row()-1);
3067       else {
3068 	l->row(0);
3069 	l->select_start_row(l->rows()-1);
3070       }
3071     }
3072     if (l->header_event==FLVE_ROW_FOOTER_CLICKED && l->rows()){
3073       if (l->last_event!=FL_PUSH)
3074 	l->row(l->row()+1);
3075       else {
3076 	l->row(l->rows()-1);
3077 	l->select_start_row(0);
3078       }
3079     }
3080     if (l->header_event==FLVE_COL_HEADER_CLICKED && l->cols()){
3081       if (l->last_event!=FL_PUSH)
3082 	l->col(l->col()-1);
3083       else {
3084 	l->col(0);
3085 	l->select_start_col(l->cols()-1);
3086       }
3087     }
3088     if (l->header_event==FLVE_COL_FOOTER_CLICKED && l->cols()){
3089       if (l->last_event!=FL_PUSH)
3090 	l->col(l->col()+1);
3091       else {
3092 	l->select_start_col(0);
3093 	l->col(l->cols()-1);
3094       }
3095     }
3096   }
3097 
finish_flv_table_gen()3098   void Flv_Table_Gen::finish_flv_table_gen(){
3099     if (Fl_Group * gr=parent()){
3100       labelsize(gr->labelsize());
3101       mb = new Fl_Menu_Button(x(),y(),w(),h(),"&Table");
3102       mb->type(Fl_Menu_Button::POPUP3);
3103       mb->box(FL_NO_BOX);
3104       mb->menu(Tableur_menu);
3105       gr->insert(*mb,gr->find(this));
3106     }
3107     else
3108       mb=0;
3109     // Style
3110     is_spreadsheet=true;
3111     header_event=0;
3112     // spread_editor = new Flve_Input( 0, 0, 0,0);
3113     // edit_when(FLV_EDIT_AUTOMATIC);
3114     // global_style.editor(spread_editor);
3115     // spread_editor->textsize(12);
3116     callback_when( FLVEcb_ROW_HEADER_CLICKED | FLVEcb_COL_HEADER_CLICKED | FLVEcb_CLICKED | FLVEcb_TITLE_CLICKED | FLVEcb_ROW_FOOTER_CLICKED | FLVEcb_COL_FOOTER_CLICKED | FLVEcb_CLICKED);
3117     callback((Fl_Callback*)Tableur_callback);
3118     select_locked(false);
3119     global_style.font_size(labelsize());
3120     global_style.x_margin(5);
3121     global_style.locked(false);
3122 
3123 #ifdef IPAQ
3124     col_width(25,-1);
3125 #else // IPAQ
3126     col_width(50,-1);
3127 #endif // IPAQ
3128     feature(FLVF_HEADERS|FLVF_ROW_FOOTER|FLVF_DIVIDERS|FLVF_MULTI_SELECT|FLVF_PERSIST_SELECT ); // add FLVF_COL_FOOTER for right footers
3129     global_style.resizable(true);
3130 #ifdef IPAQ
3131     global_style.width(40);
3132 #else // IPAQ
3133     global_style.width(10+10*labelsize());
3134 #endif // IPAQ
3135     global_style.height(labelsize()+4);
3136     row_style[-1].align(FL_ALIGN_CLIP);
3137     col_style[-1].align(FL_ALIGN_CLIP);
3138     update_status();
3139     Fl::focus(this);
3140     // Fl::focus(input);
3141   }
3142 
draw_cell(int Offset,int & X,int & Y,int & W,int & H,int R,int C)3143   void Flv_Table_Gen::draw_cell( int Offset, int &X, int &Y, int &W, int &H, int R, int C ){
3144     Flv_Style s;
3145 
3146     get_style(s, R, C);
3147     Flv_Table::draw_cell(Offset,X,Y,W,H,R,C);
3148     string ss;
3149     if (C<0){
3150       if (R>=0){
3151 	if (xcas_mode(contextptr)>0)
3152 	  ss=gen(R+1).print(contextptr);
3153 	else
3154 	  ss=gen(R).print(contextptr);
3155       }
3156     }
3157     else {
3158       if (R<0){
3159 	if (is_spreadsheet && R==-1){
3160 	  int i=C;
3161 	  for(int j=0;;++j){
3162 	    ss=char('A'+i%26-(j!=0))+ss;
3163 	    i=i/26;
3164 	    if (!i)
3165 	      break;
3166 	  }
3167 	}
3168 	else {
3169 	  if (xcas_mode(contextptr)>0)
3170 	    ss=gen(C+1).print(contextptr);
3171 	  else
3172 	    ss=gen(C).print(contextptr);
3173 	}
3174       }
3175       else {
3176 	const gen & g=m[R][C];
3177 	if ((g.type==_VECT) && (g._VECTptr->size()==3) ){
3178 	  int save_r=printcell_current_row(contextptr),save_c=printcell_current_col(contextptr);
3179 	  printcell_current_row(contextptr)=R,printcell_current_col(contextptr)=C;
3180 	  ss=pnt2string((*g._VECTptr)[1],contextptr);
3181 	  printcell_current_row(contextptr)=save_r;printcell_current_col(contextptr)=save_c;
3182 	}
3183 	else
3184 	  ss=g.print(contextptr);
3185       }
3186     }
3187     fl_color(FL_BLACK);
3188     if (ss.size()>max_printsize)
3189       ss=gettext("Too large for cell display");
3190     fl_draw(ss.c_str(), X-Offset, Y, W, H, s.align() );
3191   }
3192 
3193   /*
3194   void Flv_Table_Gen::save_editor( Fl_Widget *e, int R, int C ){
3195     if ( (R>=0) && (C>=0) ){
3196       vecteur & v=*m[R]._VECTptr;
3197       gen g(string( ((Flve_Input *) e)->value() ));
3198       if ( (v[C].type==_VECT) && (v[C]._VECTptr->size()==3)){
3199 	v[C]._VECTptr->front()=spread_convert(g,R,C);
3200 	if (is_spreadsheet) spread_eval_interrupt();
3201       }
3202       else
3203 	v[C]=g;
3204     }
3205   }
3206 
3207   void Flv_Table_Gen::load_editor( Fl_Widget *e, int R, int C ){
3208     if ((C>=0) && (R>=0)){
3209       if ( (m[R][C].type==_VECT) && (m[R][C]._VECTptr->size()==3) ){
3210 	int save_r=printcell_current_row,save_c=printcell_current_col;
3211 	printcell_current_row=R,printcell_current_col=C;
3212 	((Flve_Input *)e)->value( m[R][C][0].print(contextptr).c_str() );
3213 	printcell_current_row=save_r;printcell_current_col=save_c;
3214       }
3215       else
3216 	((Flve_Input *)e)->value( m[R][C].print(contextptr).c_str() );
3217       ((Flve_Input *)e)->position(((Flve_Input *)e)->size(), 0 );
3218     }
3219   }
3220 
3221   void Flv_Table_Gen::position_editor( Fl_Widget *e, int x, int y, int w, int h, Flv_Style &s ){
3222 
3223     //	Out of cell
3224     //	e->resize( 10, 10, 200, 20 );
3225 
3226     //	In cell
3227     //	Flv_Table::position_editor(e,x+s.x_margin(),y,w-s.x_margin(),h,s);
3228     Flv_Table::position_editor(e,x,y,w,h,s);
3229   }
3230   */
3231 
sheet2pnt(const matrice & m,vecteur & v)3232   void sheet2pnt(const matrice & m,vecteur & v){
3233     v.clear();
3234     gen tmp;
3235     const_iterateur it=m.begin(),itend=m.end();
3236     for (;it!=itend;++it){
3237       if (it->type==_VECT){
3238 	const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
3239 	for (;jt!=jtend;++jt){
3240 	  if (jt->type==_VECT && jt->_VECTptr->size()==3)
3241 	    tmp=(*jt->_VECTptr)[1];
3242 	  else
3243 	    tmp=*jt;
3244 	  bool test=tmp.is_symb_of_sommet(at_pnt);
3245 	  if (tmp.type==_VECT && !tmp._VECTptr->empty())
3246 	    test=tmp._VECTptr->back().is_symb_of_sommet(at_pnt);
3247 	  if (test)
3248 	    v.push_back(tmp);
3249 	}
3250       }
3251     }
3252   }
3253 
update_name()3254   void Flv_Table_Gen::update_name(){
3255     if (name.type==_IDNT)
3256       sto(extractmatricefromsheet(m),name,contextptr);
3257   }
3258 
update_spread_graph()3259   void Flv_Table_Gen::update_spread_graph(){
3260     // Update graph
3261     if (graph){
3262       sheet2pnt(m,graph->plot_instructions);
3263       graph2d->plot_instructions=graph->plot_instructions;
3264       if (graph3d){
3265 	graph3d->plot_instructions=graph->plot_instructions;
3266 	graph3d->redraw();
3267       }
3268       graph->redraw();
3269       graph2d->redraw();
3270     }
3271   }
3272 
spread_eval_interrupt()3273   void Flv_Table_Gen::spread_eval_interrupt(){
3274     if (computing || is_context_busy(contextptr)){
3275       fl_message("%s",gettext("CAS is busy"));
3276       return;
3277     }
3278     bool save_interrupt_button=interrupt_button;
3279     interrupt_button = true;
3280     if (is_spreadsheet){
3281       computing=true;
3282       label("Recomputing: click here to interrupt");
3283       redraw();
3284       evaled_table(contextptr)=this;
3285       thread_spread_eval(m,contextptr);
3286       update_spread_graph();
3287       computing=false;
3288     }
3289     update_name();
3290     update_status();
3291     interrupt_button=save_interrupt_button;
3292     redraw();
3293   }
3294 
3295 
3296   // Check that g is one of the following form
3297   // col1,col2...coln
3298   // cell1..row,col2,...,coln
3299   // return the corresponding submatrix of m in mselect
iscell_range(const giac::gen & g,const matrice & m,matrice & mselect,Flv_Table_Gen * sptr,int & r1,int & r2,std::vector<int> & vc,bool & absolu)3300   int iscell_range(const giac::gen & g,const matrice & m,matrice & mselect,Flv_Table_Gen * sptr,int & r1,int & r2,std::vector<int> & vc,bool & absolu){
3301     vc.clear();
3302     const giac::context * contextptr = get_context(sptr);
3303     if (g.is_symb_of_sommet(at_interval)){
3304       gen & f=g._SYMBptr->feuille;
3305       if (f.type!=_VECT || f._VECTptr->size()!=2)
3306 	return 0;
3307       int c1,c2;
3308       if (!iscell(f._VECTptr->front(),c1,r1,contextptr) || !iscell(f._VECTptr->back(),c2,r2,contextptr))
3309 	return 0;
3310       if (r1>r2)
3311 	giac::swapint(r1,r2);
3312       r2=giacmin(r2+1,m.size());
3313       r1=giacmax(r1,0);
3314       mselect=vecteur(m.begin()+r1,m.begin()+r2);
3315       mselect=mtran(mselect);
3316       if (c1>c2)
3317 	giac::swapint(c1,c2);
3318       c2=giacmin(c2+1,m.size());
3319       c1=giacmax(c1,0);
3320       mselect=vecteur(mselect.begin()+c1,mselect.begin()+c2);
3321       mselect=mtran(mselect);
3322       if (sptr){
3323 	sptr->select_start_row(r1);
3324 	if (r2)
3325 	  sptr->row(r2-1);
3326 	sptr->select_start_col(c1);
3327 	if (c2)
3328 	  sptr->col(c2-1);
3329       }
3330       for (int j=c1;j<c2;++j)
3331 	vc.push_back(j);
3332       return 1;
3333     }
3334     if (g.type!=_VECT)
3335       return 0;
3336     vecteur v=*g._VECTptr;
3337     int s=v.size();
3338     if (s<2)
3339       return 0;
3340     r1=0; r2=m.size();
3341     if (v.front().is_symb_of_sommet(at_interval) || v.front().is_symb_of_sommet(at_deuxpoints)){ // compute r1, r2
3342       gen & f=v.front()._SYMBptr->feuille;
3343       if (f.type!=_VECT || f._VECTptr->size()!=2)
3344 	return 0;
3345       vecteur & w=*f._VECTptr;
3346       int c;
3347       if (!iscell(w[0],c,r1,contextptr))
3348 	return 0;
3349       r1=giacmax(giacmin(r1,m.size()),0);
3350       if (w[1].type==_INT_)
3351 	r2=w[1].val-(xcas_mode(contextptr)!=0);
3352       else {
3353 	if (!iscell(w[1],c,r2,contextptr))
3354 	  return 0;
3355       }
3356       r2=giacmax(giacmin(r2+1,m.size()),0);
3357       if (r2<r1) giac::swapint(r1,r2);
3358     }
3359     // full columns selection
3360     matrice mt(mtran(m));
3361     int mts=mt.size();
3362     matrice tselect;
3363     for (int i=0;i<s;++i){
3364       gen h=v[i];
3365       if (h.type==_INT_ && h.val>=0 && h.val<mts){
3366 	tselect.push_back(mt[h.val]);
3367 	vc.push_back(h.val);
3368 	continue;
3369       }
3370       if (h.is_symb_of_sommet(at_interval)){
3371 	gen & f=h._SYMBptr->feuille;
3372 	if (f.type!=_VECT || f._VECTptr->size()!=2)
3373 	  return 0;
3374 	vecteur & w=*f._VECTptr;
3375 	int ca,ra,cb,rb;
3376 	if (!iscell(w[0],ca,ra,contextptr))
3377 	  return 0;
3378 	if (!iscell(w[1],cb,rb,contextptr))
3379 	  return 0;
3380 	if (ca>cb) giac::swapint(ca,cb);
3381 	if (ra>rb) giac::swapint(ra,rb);
3382 	if (ra!=r1 || rb+1!=r2)
3383 	  return 0;
3384 	for (int c=ca;c<=cb;++c){
3385 	  tselect.push_back(mt[c]);
3386 	  vc.push_back(c);
3387 	}
3388       }
3389       if (h.type!=_IDNT)
3390 	continue;
3391       absolu=true;
3392       const string & ss=h._IDNTptr->name();
3393       int sss=ss.size();
3394       if (sss<1)
3395 	return 0;
3396       int c;
3397       alphaposcell(ss,c);
3398       if (c>=0 && c<mts){
3399 	tselect.push_back(mt[c]);
3400 	vc.push_back(c);
3401       }
3402     }
3403     mselect=mtran(tselect);
3404     mselect=vecteur(mselect.begin()+r1,mselect.begin()+r2);
3405     return vc.size();
3406   }
3407 
iscell_range(const gen & g,const matrice & m,matrice & mselect,Flv_Table_Gen * sptr)3408   bool iscell_range(const gen & g,const matrice & m,matrice & mselect,Flv_Table_Gen * sptr){
3409     int r1,r2;
3410     vector<int> vc;
3411     bool absolu;
3412     return iscell_range(g,m,mselect,sptr,r1,r2,vc,absolu);
3413   }
3414 
handle(int event)3415   int Tableur_Group::handle(int event){
3416     if (table && event==FL_UNFOCUS){
3417       if (Fl::event_x()<x() || Fl::event_x()>x()+w() || Fl::event_y()<y() || Fl::event_y()>y()+h()){
3418 	// cerr << "unfocus " << '\n';
3419 	table->editing=false;
3420       }
3421     }
3422     return Fl_Tile::handle(event);
3423   }
3424 
Tableur_Group(int X,int Y,int W,int H,int L,int disp)3425   Tableur_Group::Tableur_Group(int X,int Y,int W,int H,int L,int disp):Fl_Tile(X,Y,W,H),disposition(disp),dtable(0),dgraph(0),dparam(0){
3426     labelsize(L);
3427     int l=L+6,inputh=L+18;
3428     borderbox = new Fl_Box(X,Y,w()-labelsize(),h()-labelsize());
3429     resizable(borderbox);
3430     end();
3431     box(FL_FLAT_BOX);
3432     matrice m(Flv_Table_Gen::def_rows,vecteur(Flv_Table_Gen::def_cols,0));
3433     Fl_Group::current(this);
3434     table=new Flv_Table_Gen(X,Y,W,H,m,"Spreadsheet");
3435     Fl_Group::current(this);
3436     if (!table->graph){
3437       table->graph = new Graph2d(X,Y+l,W,H-inputh,"");
3438       table->graph->ylegende=1.5;
3439     }
3440     if (!table->input){
3441       Fl_Text_Buffer * ptr=new Fl_Text_Buffer;
3442       table->input = new Xcas_Text_Editor(X,Y,W,inputh,ptr);
3443       table->input->scrollbar_width(12);
3444       table->input->buffer()->add_modify_callback(style_update, table->input);
3445       // table->input = new Multiline_Input_tab(X,Y,W,l);
3446       table->input->tableur=table;
3447       table->input->textsize(labelsize());
3448       table->input->callback(cb_Sheet_Input);
3449       table->input->tooltip(gettext("Spreadsheet commandline"));
3450       table->input->when(FL_WHEN_ENTER_KEY);
3451     }
3452     if (!table->_goto && table->input){
3453       table->_goto = new Multiline_Input_tab(X,Y,W,inputh);
3454       table->_goto->callback(cb_Spread_goto);
3455       table->_goto->textsize(labelsize());
3456       table->_goto->tooltip(gettext("Selection area"));
3457       table->_goto->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
3458     }
3459     // Attach input just after the sheet
3460     menubar = new Fl_Menu_Bar(X,Y,4*l,l);
3461     /* int s= Tableur_menu->size();
3462     Fl_Menu_Item * menuitem = new Fl_Menu_Item[s];
3463     for (int i=0;i<s;++i)
3464       *(menuitem+i)=*(Tableur_menu+i);
3465     menubar->menu (menuitem);
3466     */
3467     menubar->menu(Tableur_menu);
3468     int n=find(table)+1;
3469     insert(*table->graph,n);
3470     insert(*table->graph->mouse_param_group,n);
3471     insert(*table->input,n);
3472     insert(*table->_goto,n);
3473     insert(*menubar,n);
3474     // Add buttons here
3475     int bx=menubar->x()+menubar->w(),bs=w()-menubar->w(),by=Y,bw=3*l;
3476     if (bs<4*bw)
3477       bw=bs/4;
3478     reevalsave = new Fl_Group(bx,by,bs,H);
3479     Fl_Button * reeval=new Fl_Button(bx,by,bw,H,"eval");
3480     reeval->callback(cb_Tableur_Eval_Sheet);
3481     reeval->tooltip(gettext("Reeval current sheet"));
3482     bx += bw ; bs -= bw ;
3483     Fl_Button * seevalue=new Fl_Button(bx,by,bw,H,"val");
3484     seevalue->callback(cb_Tableur_Value);
3485     seevalue->tooltip(gettext("See value instead of formula"));
3486     bx += bw; bs -= bw;
3487     Fl_Button * reinit=new Fl_Button(bx,by,bw,H,"init");
3488     reinit->callback(cb_Tableur_Init);
3489     reinit->tooltip(gettext("Initialize the sheet using init formula"));
3490     bx += bw; bs -= bw;
3491     Fl_Button * viewgraph2d=new Fl_Button(bx,by,bw,H,"2-d");
3492     viewgraph2d->callback(cb_Tableur_Graph2d);
3493     viewgraph2d->tooltip(gettext("View attached graph 2-d"));
3494     bx += bw; bs -= bw;
3495     Fl_Button * viewgraph3d=new Fl_Button(bx,by,bw,H,"3-d");
3496     viewgraph3d->callback(cb_Tableur_Graph3d);
3497     viewgraph3d->tooltip(gettext("View attached graph 3-d"));
3498     bx += bw; bs -= bw;
3499     // Fill the remainder with an output (filename)
3500     fname =new Fl_Button(bx,by,bs,H);
3501     fname->label(gettext("<Save sheet as text>"));
3502     fname->callback(cb_Tableur_Save);
3503     fname->tooltip(gettext("Save spreadsheet independently of session"));
3504     fname->hide();
3505     reevalsave->end();
3506     insert(*reevalsave,n);
3507     change_group_fontsize(this,L);
3508     Fl_Group::current(0);
3509     table->win2=new Fl_Window(X,Y,2*W/3,2*H/3);
3510     if (!table->graph2d){
3511       table->graph2d = new Graph2d(X,Y,2*W/3,2*H/3,"");
3512       table->graph2d->ylegende=1.5;
3513     }
3514     table->win2->end();
3515     table->win2->resizable(table->win2);
3516     table->win2->hide();
3517     table->win3=0;
3518     resize2();
3519     // handle(FL_FOCUS);
3520   }
3521 
save_dparam()3522   void Tableur_Group::save_dparam(){
3523     if (disposition & 0x1){
3524       dtable=table->w();
3525       dgraph=table->graph->w();
3526       dparam=table->graph->mouse_param_group->w();
3527     }
3528     else {
3529       dtable=double(table->h())/h();
3530       dgraph=((1-dtable)*table->graph->w())/table->w();
3531       dparam=max(1-dtable-dgraph,0.05);
3532     }
3533   }
3534 
resize2(double dt,double dg,double dp)3535   void Tableur_Group::resize2(double dt,double dg,double dp){
3536     if (dt>0 && dg>0 && dp>0){
3537       dtable=dt;
3538       dgraph=dg;
3539       dparam=dp;
3540     }
3541     if (dtable<=0 || dgraph<=0 || dparam<=0 ){
3542       dtable=0.56;
3543       dgraph=0.37;
3544       dparam=0.07;
3545     }
3546     double total=dtable+dgraph+dparam;
3547     dtable/=total;
3548     dgraph/=total;
3549     dparam/=total;
3550     int X=x(),Y=y(),W=w(),H=h();
3551     int L=labelsize();
3552     int l=L+6,inputh=L+18;
3553     menubar->resize(X,Y,W/3,l);
3554     reevalsave->resize(X+W/3,Y,2*W/3,l);
3555     if (disposition/2){
3556       if (disposition %2){ // table || graph
3557 	int itable=int(W*dtable+.5);
3558 	int igraph=int(W*dgraph+.5);
3559 	table->_goto->resize(X,Y+l,itable/3,inputh);
3560 	table->input->resize(X+itable/3,Y+l,itable-itable/3,inputh);
3561 	int itg=itable+igraph;
3562 	table->resize(X,Y+l+inputh,itable,H-l-inputh);
3563 	if (table->mb)
3564 	  table->mb->resize(X,Y+l+inputh,itable,H-l-inputh);
3565 	table->graph->resize(X+itable,Y+l,igraph,H-l);
3566 	/*
3567 	table->graph->mouse_param_group->resize(X+itg,Y+l,W-itg,H-l);
3568 	int hh=(H-l);
3569 	if (hh>8*labelsize())
3570 	  hh=8*labelsize();
3571 	table->graph->mouse_position->resize(X+itg,Y+l,W-itg,hh/4);
3572 	table->graph->button_group->resize(X+itg,Y+l+hh/4,W-itg,hh/2);
3573 	*/
3574 	table->graph->resize_mouse_param_group(W-itg);
3575       }
3576       else { // graph below
3577 	table->_goto->resize(X,Y+l,W/4,inputh);
3578 	table->input->resize(X+W/4,Y+l,3*W/4,inputh);
3579 	int itable=int(H*dtable+.5);
3580 	int igraph=int(W*dgraph/(dgraph+dparam)+.5);
3581 	table->resize(X,Y+l+inputh,W,itable);
3582 	if (table->mb)
3583 	  table->mb->resize(X,Y+l+inputh,W,itable);
3584 	table->graph->resize(X,Y+l+inputh+itable,igraph,H-itable-l-inputh);
3585 	/*
3586 	int hh=H-itable-2*l;
3587 	if (hh>8*labelsize())
3588 	  hh=8*labelsize();
3589 	int Y1=Y+2*l+itable;
3590 	table->graph->mouse_param_group->resize(X+igraph,Y1,W-igraph,hh);
3591 	int dh=hh/4;
3592 	table->graph->mouse_position->resize(X+igraph,Y1,W-igraph,dh);
3593 	table->graph->button_group->resize(X+igraph,Y1+dh,W-igraph,hh/2);
3594 	dh += hh/2;
3595 	*/
3596 	table->graph->resize_mouse_param_group(W-igraph);
3597       }
3598       table->graph->show();
3599       table->graph->mouse_param_group->show();
3600     }
3601     else {
3602       table->resize(X,Y+l+inputh,W,H-l-inputh);
3603       if (table->mb)
3604 	table->mb->resize(X,Y+l+inputh,W,H-(l+inputh));
3605       table->_goto->resize(X,Y+l,W/4,inputh);
3606       table->input->resize(X+W/4,Y+l,3*W/4,inputh);
3607       table->graph->resize(X,Y+H,5*W/6,0);
3608       table->graph->mouse_param_group->resize(X+5*W/6,Y+H,W/6,0);
3609       table->graph->hide();
3610       table->graph->mouse_param_group->hide();
3611     }
3612     redraw();
3613     init_sizes();
3614   }
3615 
Xcas_fltk_Row(const gen & g,GIAC_CONTEXT)3616   gen Xcas_fltk_Row(const gen & g,GIAC_CONTEXT){
3617     Flv_Table_Gen * tptr=(Flv_Table_Gen * )evaled_table(contextptr);
3618     if (tptr)
3619       return tptr->row();
3620     return -1;
3621   }
3622 
Xcas_fltk_current_sheet(const gen & g,GIAC_CONTEXT)3623   gen Xcas_fltk_current_sheet(const gen & g,GIAC_CONTEXT){
3624     Flv_Table_Gen * tptr=(Flv_Table_Gen * )evaled_table(contextptr);
3625     if (tptr){
3626       const giac::context * contextptr = get_context((tptr));
3627       int r,c;
3628       if (iscell(g,c,r,contextptr)){
3629 	if (r>=tptr->rows()||c>=tptr->cols())
3630 	  return undef;
3631 	gen tmp=tptr->m[r];
3632 	tmp=tmp[c];
3633 	return tmp[1];
3634       }
3635       if (g.type==_VECT && g._VECTptr->size()==2 && g._VECTptr->front().type==_INT_ && g._VECTptr->back().type==_INT_)
3636 	return gen(extractmatricefromsheet(tptr->m),_MATRIX__VECT)[g];
3637       if (iscell_range(g,tptr->m,tptr->selected,tptr) ){
3638 	return extractmatricefromsheet(tptr->selected);
3639       }
3640       return  gen(extractmatricefromsheet(tptr->m),_MATRIX__VECT)[g];
3641     }
3642     return 0;
3643   }
3644 
Xcas_fltk_Col(const gen & g,GIAC_CONTEXT)3645   gen Xcas_fltk_Col(const gen & g,GIAC_CONTEXT){
3646     Flv_Table_Gen * tptr=(Flv_Table_Gen * )evaled_table(contextptr);
3647     if (tptr)
3648       return tptr->col();
3649     return -1;
3650   }
3651 
3652 #ifndef NO_NAMESPACE_XCAS
3653 } // namespace xcas
3654 #endif // ndef NO_NAMESPACE_XCAS
3655 
3656 #endif // HAVE_LIBFLTK
3657