1 // -*- mode:C++ ; compile-command: "g++ -DHAVE_CONFIG_H -I. -I.. -I/usr/local/include -g -c History.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) 2005,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 <FL/Fl.H>
29 #include <FL/fl_draw.H>
30 #include <FL/Fl_Window.H>
31 #include <FL/Fl_Tile.H>
32 #include <FL/fl_ask.H>
33 #include <FL/Fl_File_Chooser.H>
34 #include "History.h"
35 #include "Input.h"
36 #include "Equation.h"
37 #include "Print.h"
38 #include "Graph.h"
39 #include "Graph3d.h"
40 #include "Tableur.h"
41 #include "Editeur.h"
42 #include "Cfg.h"
43 #ifndef IN_GIAC
44 #include <giac/tex.h>
45 #else
46 #include "tex.h"
47 #endif
48 #include <FL/Fl_Multiline_Output.H>
49 #include <iostream>
50 #include <fstream>
51 #ifdef HAVE_MALLOC_H
52 #include <malloc.h>
53 #endif
54 #ifdef HAVE_SSTREAM
55 #include <sstream>
56 #else
57 #include <strstream>
58 #endif
59 #ifdef WIN32
60 #ifndef GNUWINCE
61 #include <sys/cygwin.h>
62 #endif
63 #endif
64 #ifdef HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
67 
68 using namespace std;
69 using namespace giac;
70 
71 #ifdef HAVE_LIBFLTK
72 #if defined(FL_DEVICE) || (!defined(__APPLE__) && !defined(WIN32))
73 #include <FL/Fl_File_Chooser.H>
file_chooser(const char * message,const char * pat,const char * fname,int relative)74 char *file_chooser(const char *message,const char *pat,const char *fname,int relative){
75   return fl_file_chooser(message,pat,fname,relative);
76 }
load_file_chooser(const char * message,const char * pat,const char * fname,int relative,bool save)77 char *load_file_chooser(const char *message,const char *pat,const char *fname,int relative,bool save){
78   return fl_file_chooser(message,pat,fname,relative);
79 }
80 #else // FL_DEVICE
81 #include <FL/Fl_Native_File_Chooser.H>
load_file_chooser(const char * message,const char * pat,const char * fname,int relative,bool save)82 char *load_file_chooser(const char *message,const char *pat,const char *fname,int relative,bool save){
83   // Create native chooser
84   Fl_Native_File_Chooser native(Fl_Native_File_Chooser::BROWSE_FILE);
85   static string filename="";
86   string path(pat);
87   int l=path.find('\n');
88   if (l<0 || l>=int(path.size()))
89     path += '\n';
90   native.title(message);
91   if (save)
92     native.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
93   else
94     native.type(Fl_Native_File_Chooser::BROWSE_FILE);
95   native.filter(path.c_str());
96   // native.filter("Text\t*.txt\n");
97   native.preset_file(fname);
98   // Show native chooser
99   switch ( native.show() ) {
100   case -1:
101     return 0;	// ERROR
102   case  1:
103     return 0;		// CANCEL
104   default: // PICKED FILE
105     filename=native.filename();
106     fname=filename.c_str();
107     return (char *) filename.c_str();
108   }
109 }
110 
111 
112 #if 0 // def __APPLE__
113 Fl_Input * file_chooser_filename = NULL;
114 Fl_Window * file_chooser_win =0;
115 Fl_Button * file_chooser_but1=0;
116 Fl_Button * file_chooser_but2=0;
117 Fl_Button * file_chooser_but3=0;
118 
119 char *file_chooser(const char *message,const char *pat,const char *fname,int relative){
120   if (!file_chooser_win){
121     Fl_Group::current(0);
122     file_chooser_win = new Fl_Window(600, 80,gettext("Choose file"));
123     file_chooser_win->begin();
124     int y = 10;
125     file_chooser_filename = new Fl_Input(100, y, file_chooser_win->w()-120, 25, gettext("Filename"));
126     if (fname) file_chooser_filename->value(fname);
127     file_chooser_filename->tooltip(gettext("Current filename"));
128     y += file_chooser_filename->h() + 5;
129     file_chooser_but1 = new Fl_Button(20, y, file_chooser_win->w()/3-40, 25, gettext("Choose file to overwrite"));
130     file_chooser_but2 = new Fl_Button(file_chooser_win->w()/3+20, y,file_chooser_win->w()/3-40, 25, gettext("OK"));
131     file_chooser_but3 = new Fl_Button(2*file_chooser_win->w()/3+20, y,file_chooser_win->w()/3-40, 25, gettext("Cancel"));
132     y += file_chooser_filename->h() + 5;
133     file_chooser_win->end();
134   }
135   file_chooser_win->set_modal();
136   file_chooser_win->show();
137   file_chooser_win->hotspot(file_chooser_win);
138   int r=-1;
139   for (;r<0;) {
140     Fl_Widget *o = Fl::readqueue();
141     if (!o) Fl::wait();
142     else {
143       if (o == file_chooser_but1){
144 	Fl_Native_File_Chooser native(Fl_Native_File_Chooser::BROWSE_FILE);
145 	string path(pat);
146 	int l=path.find('\n');
147 	if (l<0 || l>=path.size())
148 	  path += '\n';
149 	native.title(message);
150 	native.type(Fl_Native_File_Chooser::BROWSE_FILE);
151 	native.filter(path.c_str());
152 	// native.filter("Text\t*.txt\n");
153 	native.preset_file(fname);
154 	// Show native chooser
155 	switch ( native.show() ) {
156 	case -1: // Error
157 	  fl_alert("%s",(string(gettext("Error"))+native.errmsg()).c_str());
158 	  break;
159 	case  1: // Cancel
160 	  break;
161 	default:
162 	  if ( native.filename() ) {
163 	    file_chooser_filename->value(native.filename());
164 	    file_chooser_filename->position(0,0);
165 	  } else {
166 	    file_chooser_filename->value("<filename>");
167 	  }
168 	  break;
169 	}
170       }
171       if (o == file_chooser_but2) r = 2; // ok
172       if (o == file_chooser_but3) r = 3; // cancel
173     }
174   } // end for (;r<0;)
175   file_chooser_win->hide();
176   if (r==2)
177     return (char *)(file_chooser_filename->value());
178   else
179     return 0;
180 }
181 #else
file_chooser(const char * message,const char * pat,const char * fname,int relative)182 char *file_chooser(const char *message,const char *pat,const char *fname,int relative){
183   return load_file_chooser(message,pat,fname,relative,true);
184 }
185 #endif // __APPLE__
186 
187 #endif // FL_DEVICE
188 #endif // HAVE_LIBFLTK
189 
190 #ifndef NO_NAMESPACE_XCAS
191 namespace xcas {
192 #endif // ndef NO_NAMESPACE_XCAS
193 
194   static std::vector<std::string> Xcas_recent_filenames;
195   static std::string Xcas_recent_filenames_filename("xcas_recent");
196   void (*Xcas_load_filename)(const char * filename,bool modified)=0;
197   static const unsigned Xcas_recent_filenames_size=10;
198   static Fl_Menu_ * recent_filenames_menu=0;
199 
cb_recent_filename(Fl_Widget * wid,void * ptr)200   void cb_recent_filename(Fl_Widget * wid , void* ptr){
201     Fl_Menu_ * M =dynamic_cast<Fl_Menu_ *>(wid);
202     if (!M)
203       return ;
204     const Fl_Menu_Item * m=M->mvalue();
205     unsigned n=0;
206     for (--m;;++n,--m){
207       if (m->submenu())
208 	break;
209     }
210     if (n==0 || n>Xcas_recent_filenames.size())
211       return ;
212     if (Xcas_load_filename)
213       (*Xcas_load_filename)(Xcas_recent_filenames[n-1].c_str(),false);
214   }
add_recent_filename(const std::string & s,bool writerecent)215   void add_recent_filename(const std::string & s,bool writerecent){
216     Fl_Menu_ * menu = recent_filenames_menu;
217     string s_=remove_path(s);
218     if (s_.substr(0,10)=="xcas_auto_")
219       return;
220     unsigned i=0;
221     for (;i<Xcas_recent_filenames.size();++i){
222       if (s_==remove_path(Xcas_recent_filenames[i]))
223 	break;
224     }
225     if (i==Xcas_recent_filenames.size()){
226       Xcas_recent_filenames.push_back(s);
227       int offset=menu->add((gettext("File")+string("/")+gettext("Open")+string("/")+remove_path(s)).c_str(),0,(Fl_Callback*)cb_recent_filename);
228       if (Xcas_recent_filenames.size()>Xcas_recent_filenames_size){
229 	Xcas_recent_filenames.erase(Xcas_recent_filenames.begin());
230 	menu->remove(4);
231       }
232       menu->textsize(menu->labelsize());
233       if (writerecent){
234 #ifdef WIN32
235 	ofstream of((giac::xcasroot()+Xcas_recent_filenames_filename).c_str());
236 #else
237 	ofstream of((giac::home_directory()+Xcas_recent_filenames_filename).c_str());
238 #endif
239 	for (unsigned i=0;i<Xcas_recent_filenames.size();++i)
240 	  of << Xcas_recent_filenames[i] << '\n';
241 	of.close();
242       }
243     }
244   }
read_recent_filenames(Fl_Menu_ * menu)245   void read_recent_filenames(Fl_Menu_ * menu){
246     recent_filenames_menu=menu;
247 #ifdef WIN32
248     return;
249     ifstream of((giac::xcasroot()+Xcas_recent_filenames_filename).c_str());
250 #else
251     ifstream of((giac::home_directory()+Xcas_recent_filenames_filename).c_str());
252 #endif
253     Xcas_recent_filenames.clear();
254     for (;;){
255       char buf[65536];
256       of.getline(buf,65535);
257       if (!of)
258 	break;
259       add_recent_filename(buf,false);
260     }
261   }
262   std::string autosave_folder;
263   int GRABAREA=4;
264   bool fl_handle_lock=false; // True when Fl::handle is busy
265   int labeladd=6;
266   Fl_Output * Parse_error_output = 0;
267   owstream * logstream = 0;
268   Fl_Color Xcas_input_color=FL_BLACK,Xcas_input_background_color=FL_WHITE,
269     Xcas_comment_color=FL_DARK_GREEN,Xcas_comment_background_color=FL_WHITE,
270     Xcas_log_color=0x3a,Xcas_log_background_color=FL_WHITE,
271     Xcas_equation_input_color=FL_BLACK,Xcas_equation_input_background_color=FL_WHITE,
272     Xcas_equation_color=FL_BLUE,Xcas_equation_background_color=FL_WHITE,
273     Xcas_editor_color=FL_BLACK,Xcas_editor_background_color=FL_WHITE,
274     Xcas_background_color =FL_GRAY;
275   int Xcas_save_saved_color=FL_VERT_PALE,Xcas_save_unsaved_color=FL_ROUGE_PALE;
276   // NB search for 167/211 for save button color
277   void (* Keyboard_Switch )(unsigned)=0;
278 
set_colors(Fl_Widget * w,bool do_redraw)279   void set_colors(Fl_Widget * w,bool do_redraw){
280     if (do_redraw)
281       w->redraw();
282     if (Fl_Group * g= dynamic_cast<Fl_Group *>(w)){
283       int n=g->children();
284       for (int i=0;i<n;++i)
285 	set_colors(g->child(i));
286       return;
287     }
288     if (Comment_Multiline_Input * c=dynamic_cast<Comment_Multiline_Input *>(w)){
289       c->textcolor(Xcas_comment_color);
290       c->color(Xcas_comment_background_color);
291       return;
292     }
293     if (Multiline_Input_tab * i=dynamic_cast<Multiline_Input_tab *>(w)){
294       i->textcolor(Xcas_input_color);
295       i->color(Xcas_input_background_color);
296       return;
297     }
298     if (Equation * eq=dynamic_cast<Equation *>(w)){
299       eq->attr.text_color=eq->output_equation?Xcas_equation_color:Xcas_equation_input_color;
300       eq->color(eq->output_equation?Xcas_equation_background_color:Xcas_equation_input_background_color);
301       return;
302     }
303     if (Log_Output * lg =dynamic_cast<Log_Output *>(w)){
304       lg->textcolor(Xcas_log_color);
305       lg->color(Xcas_log_background_color);
306       return;
307     }
308     if (Editeur * ed=dynamic_cast<Editeur *>(w)){
309       ed->color(Xcas_editor_background_color);
310       return;
311     }
312     if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(w)){
313       ed->color(Xcas_editor_background_color);
314       return;
315     }
316     if (dynamic_cast<Fl_Menu_ *>(w))
317       w->color(Xcas_background_color);
318   }
319 
max(int i,int j)320   static inline int max(int i,int j){
321     if (i>j)
322       return i;
323     else
324       return j;
325   }
326 
min(int i,int j)327   static inline int min(int i,int j){
328     if (i>j)
329       return j;
330     else
331       return i;
332   }
333 
abs(int x)334   static inline int abs(int x){
335     if (x<0) return -x; else return x;
336   }
337 
History_Pack(int X,int Y,int W,int H,const char * l)338   History_Pack::History_Pack(int X,int Y,int W,int H,const char*l):Fl_Group(X,Y,W,H,l),_selecting(false),_pushed(false),_moving(false),_saving(false),undo_position(0),_modified(false),_resize_above(false),_spacing(2),_printlevel_w(labelsize()),_sel_begin(-1),_sel_end(-1),pretty_output(1),next_delay(0),eval_below(false),doing_eval(false),eval_below_once(true),eval_next(false),queue_pos(-1),update_pos(-1),contextptr(0),
339 #if 1
340 								   new_question(new_question_editor),
341 #else
342 								   new_question(new_question_multiline_input),
343 #endif
344 								   _select(0),_insert(0),url(0),eval(0) {
345     box(FL_FLAT_BOX);
346     end();
347     set_colors(this,false);
348     if (parent()){
349       labelsize(parent()->labelsize());
350       labelfont(parent()->labelfont());
351     }
352     parent_redraw(this);
353   }
354 
set_sel_begin(const Fl_Widget * w)355   int History_Pack::set_sel_begin(const Fl_Widget * w){
356     if (_sel_begin!=-1)
357       return _sel_begin;
358     _sel_begin=_sel_end=-1;
359     for (;w;){
360       if (w->parent()==this)
361 	break;
362       w=w->parent();
363     }
364     if (w)
365       return _sel_begin=find(w);
366     else
367       return -1;
368   }
369 
focus(const Fl_Widget * w) const370   int History_Pack::focus(const Fl_Widget * w) const {
371     for (;w;){
372       if (w->parent()==this)
373 	break;
374       w=w->parent();
375     }
376     if (w)
377       return find(w);
378     else
379       return -1;
380   }
381 
set_scroller(Fl_Group * gr)382   void History_Pack::set_scroller(Fl_Group * gr){
383     if (!gr)
384       return;
385     if (Fl_Scroll * s = dynamic_cast<Fl_Scroll *>(parent())){
386       Fl_Widget * ch=gr->child(0);
387       int spos=s->yposition();
388       int chpos=ch->y()-y();
389       int sh=s->h()-10;
390       if (chpos<spos)
391 #ifdef _HAVE_FL_UTF8_HDR_
392 	s->scroll_to(0,max(0,min(chpos,h()-sh)));
393 #else
394       s->position(0,max(0,min(chpos,h()-sh)));
395 #endif
396       else {
397 	if (chpos+gr->h()>spos+sh)
398 #ifdef _HAVE_FL_UTF8_HDR_
399 	  s->scroll_to(0,chpos+gr->h()-sh);
400 #else
401 	s->position(0,chpos+gr->h()-sh);
402 #endif
403 	else
404 #ifdef _HAVE_FL_UTF8_HDR_
405 	  s->scroll_to(0,spos);
406 #else
407 	s->position(0,spos);
408 #endif
409       }
410       s->redraw();
411     }
412   }
413 
414   // Focus on history pack level no pos if it's an input
focus(int pos,bool do_focus)415   bool History_Pack::focus(int pos,bool do_focus){
416     if (pos>=children() || pos<0)
417       pos=children()-1;
418     if (pos<0)
419       return false;
420     Fl_Tile * gr=dynamic_cast<Fl_Tile *>(child(pos));
421     if (gr && gr->children()){
422       Fl_Widget * ch=gr->child(0);
423       if (do_focus){
424 	if (Fl_Input_ * in=dynamic_cast<Fl_Input_ *>(ch)){
425 	  in->position(in->position(),in->position());
426 	}
427 	if (Fl::focus())
428 	  Fl::focus()->damage(FL_DAMAGE_ALL);
429 	Fl::belowmouse(ch);
430 	Fl::focus(ch);
431 	ch->handle(FL_FOCUS);
432 	ch->damage(FL_DAMAGE_ALL);
433 	ch->redraw();
434       }
435       // set the scroller if there is one above
436       set_scroller(gr);
437       if (Editeur * ed = dynamic_cast<Editeur *>(ch)){
438 	if (do_focus)
439 	  Fl::focus(ed->editor);
440       }
441       if (Xcas_Text_Editor * ed = dynamic_cast<Xcas_Text_Editor *>(ch)){
442 	if (do_focus)
443 	  Fl::focus(ed);
444       }
445       return true;
446     }
447     return false;
448   }
449 
warn_equal(const giac::gen & g,GIAC_CONTEXT)450   giac::gen warn_equal(const giac::gen & g,GIAC_CONTEXT){
451     if (g.is_symb_of_sommet(at_of)){
452       gen f=g._SYMBptr->feuille;
453       if (f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->front().type==_IDNT && f._VECTptr->back().type==_VECT){
454 	gen n=f._VECTptr->front(),n1;
455 	gen arg=f._VECTptr->back();
456 	size_t s=arg._VECTptr->size();
457 	if ((s==2 || s==3) && !n._IDNTptr->in_eval(0,n,n1,contextptr,true))
458 	  *logptr(contextptr) << gettext("If you want to create a point ") << n
459 			      << gettext(" with coordinates ") << arg << '\n'
460 			      << gettext("the right command is ") << n <<":=point(" << arg << ")" << '\n';
461       }
462     }
463     if (python_compat(contextptr)==0 && g.is_symb_of_sommet(at_equal) && g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2 && g._SYMBptr->feuille._VECTptr->front().type!=_INT_){
464       if (g._SYMBptr->feuille._VECTptr->front().is_symb_of_sommet(at_at) || g._SYMBptr->feuille._VECTptr->front().is_symb_of_sommet(at_of) || g._SYMBptr->feuille._VECTptr->front().type!=_SYMB)
465 	*logptr(contextptr) << gettext("Warning evaluating = at top level, you must use := to assign ") << g._SYMBptr->feuille._VECTptr->back() << gettext(" to ") << g._SYMBptr->feuille._VECTptr->front() << gettext(" or == to test equality") << '\n';
466     }
467     return equaltosto(g,contextptr);
468   }
469 
parse(Fl_Widget * w,giac::gen & g)470   int parse(Fl_Widget * w,giac::gen & g){
471     const context * contextptr=context0;
472     const  History_Pack * whp = get_history_pack(w);
473     if (whp)
474       contextptr = whp->contextptr;
475     else
476       contextptr=get_context(w);
477     if (Multiline_Input_tab * m=dynamic_cast<Multiline_Input_tab *>(w)){
478       if (m && !m->changed()){
479 	g = warn_equal(m->g(),contextptr);
480 	return !is_undef(g);
481       }
482       if (!*m->value())
483 	return 0;
484       g=warn_equal(giac::gen(m->value(),contextptr),contextptr);
485       if (m)
486 	m->_g=g;
487       if (giac::first_error_line(contextptr))
488 	*logptr(contextptr) << gettext("Syntax compatibility mode ") << print_program_syntax(xcas_mode(contextptr)) << gettext("\nParse error line ") << giac::first_error_line(contextptr) + gettext(" column ")+print_INT_(giac::lexer_column_number(contextptr))+  gettext(" at ")  << giac::error_token_name(contextptr) ;
489       return 1;
490     }
491     if (Equation * e = dynamic_cast<Equation *>(w)){
492       e->parse_desactivate();
493       e->select();
494       g=e->get_data();
495       return 1;
496     }
497     if (Editeur * ed=dynamic_cast<Editeur *>(w))
498       return parse(ed->editor,g);
499     if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(w)){
500       if (ed->buffer()->length()==0)
501 	return 0;
502       if (!ed->changed()){
503 	g = warn_equal(ed->g(),contextptr);
504 	return !is_undef(g);
505       }
506       g=warn_equal(giac::gen(ed->value(),contextptr),contextptr);
507       if (ed)
508 	ed->_g=g;
509       if (giac::first_error_line(contextptr))
510 	*logptr(contextptr) << gettext("Syntax compatibility mode ") << print_program_syntax(xcas_mode(contextptr)) << gettext("\nParse error line ") << giac::first_error_line(contextptr) << gettext(" column ") << print_INT_(giac::lexer_column_number(contextptr)) <<  gettext(" at ")  << giac::error_token_name(contextptr) ;
511       return 1;
512     }
513     if (Figure * f = dynamic_cast<Figure *>(w)){
514       if (f->geo && f->geo->hp){
515 	if (whp)
516 	  f->geo->hp->eval_next=whp->eval_below;
517 	f->geo->hp->update();
518 	return -1;
519       }
520     }
521     if (History_Fold * hf=dynamic_cast<History_Fold *>(w)){
522       hf->eval();
523       return -1;
524     }
525     if (History_Pack * hp=dynamic_cast<History_Pack *>(w)){
526       hp->update(0);
527       return -1;
528     }
529     const History_Pack * hp = get_history_pack(w);
530     if (Tableur_Group * t=dynamic_cast<Tableur_Group *>(w)){
531       Flv_Table_Gen * tg = t->table;
532       if (hp)
533 	tg->contextptr=hp->contextptr;
534       tg->spread_eval_interrupt();
535     }
536     return 0;
537   }
538 
value(int n) const539   std::string History_Pack::value(int n) const {
540     int m=children();
541     if (n<0 || n>=m)
542       return "undef";
543     Fl_Widget * wid = child(n);
544     if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
545       if(s->children())
546 	wid=s->child(0);
547     if (Fl_Group * g=dynamic_cast<Fl_Group *>(wid))
548       if (g->children())
549 	wid=g->child(0);
550     if (Fl_Input * i = dynamic_cast<Fl_Input *>(wid))
551       return i->value();
552     if (Xcas_Text_Editor * i = dynamic_cast<Xcas_Text_Editor *>(wid))
553       return i->value();
554     if (Equation * e = dynamic_cast<Equation *>(wid)){
555       e->parse_desactivate();
556       e->select();
557       gen g=e->get_data();
558       return g.print(contextptr).c_str();
559     }
560     return "undef";
561   }
562 
parse(int n)563   giac::gen History_Pack::parse(int n){
564     int m=children();
565     if (n>=m){
566       n=m;
567       add_entry(-1);
568       ++m;
569     }
570     Fl_Widget * wid = child(n);
571     if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
572       if(s->children())
573 	wid=s->child(0);
574     if (Fl_Group * g=dynamic_cast<Fl_Group *>(wid))
575       if (g->children())
576 	wid=g->child(0);
577     gen res;
578     if (!xcas::parse(wid,res))
579       return undef;
580     return res;
581   }
582 
set_gen_value(Fl_Widget * w,const giac::gen & g,bool exec)583   bool set_gen_value(Fl_Widget * w,const giac::gen & g,bool exec){
584     const giac::context * contextptr = get_context(w);
585     if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(w)){
586       ed->_g=g;
587       bool res=set_value(ed,g.print(contextptr),exec);
588       ed->clear_gchanged();
589       return res;
590     }
591     if (Fl_Input_ * i = dynamic_cast<Fl_Input_ *>(w)){
592       i->value(g.print(contextptr).c_str());
593       i->position(0,0);
594       if (Multiline_Input_tab * m = dynamic_cast<Multiline_Input_tab *>(i)){
595 	m->_g=g;
596 	i->clear_changed();
597       }
598       else
599 	i->set_changed();
600       if (exec)
601 	i->do_callback();
602       return true;
603     }
604     if (Equation * e = dynamic_cast<Equation *>(w)){
605       e->parse_desactivate();
606       e->select();
607       e->set_data(g);
608       if (exec)
609 	e->do_callback();
610       return true;
611     }
612     return false;
613   }
614 
set_gen_value(int n,const gen & g,bool exec)615   void History_Pack::set_gen_value(int n,const gen & g,bool exec){
616     int m=children();
617     if (n<0 || n>=m){
618       if (value(m-1)!=""){
619 	n=m;
620 	add_entry(-1);
621 	++m;
622       }
623       else
624 	n=m-1;
625     }
626     if (is_context_busy(contextptr) || doing_eval){
627       queue_val=g;
628       queue_pos=n;
629     }
630     else {
631       Fl_Widget * wid = child(n);
632       if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
633 	if(s->children())
634 	  wid=s->child(0);
635       if (Fl_Group * g=dynamic_cast<Fl_Group *>(wid))
636 	if (g->children())
637 	  wid=g->child(0);
638       xcas::set_gen_value(wid,g,exec);
639     }
640   }
641 
widget_group(int n)642   Fl_Group * History_Pack::widget_group(int n){
643     int m=children();
644     if (n<0 || n>=m)
645       return 0;
646     Fl_Widget * wid = child(n);
647     if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
648       if(s->children())
649 	wid=s->child(0);
650     if (Fl_Group * g=dynamic_cast<Fl_Group *>(wid))
651       return g;
652     return 0;
653   }
654 
set_value(Fl_Widget * w,const std::string & s,bool exec)655   bool set_value(Fl_Widget * w,const std::string & s,bool exec){
656     context * contextptr=get_context(w);
657     if (Fl_Input_ * i = dynamic_cast<Fl_Input_ *>(w)){
658       i->value(s.c_str());
659       i->position(0,0);
660       i->set_changed();
661       if (exec)
662 	i->do_callback();
663       return true;
664     }
665     if (Xcas_Text_Editor * i = dynamic_cast<Xcas_Text_Editor *>(w)){
666       if (i->buffer()->length()>0)
667 	i->buffer()->remove(0,i->buffer()->length());
668       i->buffer()->insert(0,s.c_str());
669       i->insert_position(0);
670       i->set_gchanged();
671       if (exec)
672 	i->do_callback();
673       return true;
674     }
675     if (Equation * e = dynamic_cast<Equation *>(w)){
676       e->parse_desactivate();
677       e->select();
678       e->set_data(gen(s,contextptr));
679       if (exec)
680 	e->do_callback();
681       return true;
682     }
683     return false;
684   }
685 
set_value(int n,const std::string & s,bool exec)686   void History_Pack::set_value(int n,const std::string & s,bool exec){
687     int m=children();
688     if (n<0 || n>=m){
689       if (value(m-1)!=""){
690 	n=m;
691 	add_entry(-1);
692 	++m;
693       }
694       else
695 	n=m-1;
696     }
697     Fl_Widget * wid = child(n);
698     if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
699       if(s->children())
700 	wid=s->child(0);
701     if (Fl_Group * g=dynamic_cast<Fl_Group *>(wid))
702       if (g->children())
703 	wid=g->child(0);
704     xcas::set_value(wid,s,exec);
705   }
706 
get_history_fold(const Fl_Widget * wid)707   History_Fold * get_history_fold(const Fl_Widget * wid){
708     History_Fold * f =0 ;
709     if (!wid)
710       return f;
711     Fl_Group * w=wid->parent();
712     for (;w;w=w->parent()){
713       if ( (f=dynamic_cast<History_Fold *>(w)) )
714 	break;
715     }
716     return f;
717   }
718 
get_history_fold_focus(const Fl_Widget * wid)719   History_Fold * get_history_fold_focus(const Fl_Widget * wid){
720     History_Fold * f=get_history_fold(xcas::Xcas_input_focus);
721     return f?f:get_history_fold(wid);
722   }
723 
get_history_pack(const Fl_Widget * w,int & pos)724   History_Pack * get_history_pack(const Fl_Widget * w,int & pos){
725     pos = -1;
726     if (!w)
727       return 0;
728     Fl_Group * g = w->parent();
729     if (History_Pack * h = dynamic_cast<History_Pack *>(g)){
730       pos=h->find(w);
731       return h;
732     }
733     return get_history_pack(g,pos);
734   }
735 
get_history_pack(const Fl_Widget * w)736   History_Pack * get_history_pack(const Fl_Widget * w){
737     int pos;
738     return get_history_pack(w,pos);
739   }
740 
get_history_pack2(const Fl_Widget * w)741   History_Pack * get_history_pack2(const Fl_Widget * w){
742     if (!w)
743       return 0;
744     if (const History_Pack * h = dynamic_cast<const History_Pack *>(w))
745       return (History_Pack *) h;
746     if (const History_Fold * h = dynamic_cast<const History_Fold *>(w))
747       return (History_Pack *) h->pack;
748     return get_history_pack2(w->parent());
749   }
750 
get_context(const Fl_Widget * w)751   context * get_context(const Fl_Widget * w){
752     const History_Pack * hp = get_history_pack2(w);
753     if (hp)
754       return hp->contextptr;
755     if (const Flv_Table_Gen * t=dynamic_cast<const Flv_Table_Gen *>(w))
756       return t->contextptr;
757     if (const Tableur_Group * gr = dynamic_cast<const Tableur_Group *>(w))
758       return gr->table->contextptr;
759     return 0;
760   }
761 
set_context(Fl_Widget * w,giac::context * contextptr)762   void set_context(Fl_Widget * w,giac::context * contextptr){
763     if (Graph2d3d *gr=dynamic_cast<Graph2d3d *>(w))
764       gr->no_handle=false;
765     Fl_Group * g=dynamic_cast<Fl_Group *>(w);
766     if (!g)
767       return;
768     if (History_Pack * hp=dynamic_cast<History_Pack *>(g))
769       hp->contextptr=contextptr;
770     if (Logo * l=dynamic_cast<Logo *>(g))
771       l->t->turtleptr=&giac::turtle_stack(contextptr);
772     int n=g->children();
773     for (int i=0;i<n;++i){
774       set_context(g->child(i),contextptr);
775     }
776   }
777 
clear_modified()778   void History_Fold::clear_modified(){
779     if (fold_button){
780       fold_button->color(Xcas_save_saved_color);
781       fold_button->redraw();
782     }
783     if (save_button){
784       save_button->color(Xcas_save_saved_color);
785       save_button->redraw();
786     }
787   }
788 
clear_modified()789   void History_Pack::clear_modified(){
790     _modified = false ;
791     if (History_Fold * f = get_history_fold(this))
792       f->clear_modified();
793     int n=children();
794     for (int i=0;i<n;++i){
795       if (History_Fold * f = dynamic_cast<History_Fold *>(child(i)))
796 	f->clear_modified();
797     }
798   }
799 
restore(int dpos)800   void History_Pack::restore(int dpos){
801     int undo_pos_save=undo_position;
802     int us=undo_history.size();
803     if (undo_position==us){
804       if (dpos>=0)
805 	return;
806       if (dpos==-1){
807 	backup();
808 	undo_position -=2;
809 	++us;
810       }
811     }
812     if (undo_position<=0 && dpos<0)
813       return;
814     undo_position += dpos;
815     if (undo_position<0)
816       undo_position=0;
817     if (us){
818       if (undo_position>=us)
819 	undo_position=us-1;
820       vector<Fl_Widget *> & cur =undo_history[undo_position];
821       int curs=cur.size();
822       // delete child widgets that are not inside cur
823       int ns=children();
824       for (int i=ns-1;i>=0;--i){
825 	Fl_Widget * wid=child(i);
826 	int j=0;
827 	for (;j<curs;++j){
828 	  if (cur[j]==wid)
829 	    break;
830 	}
831 	if (j==curs){
832 	  add_history_map(wid,undo_pos_save);
833 	  remove(wid);
834 	  delete wid;
835 	}
836 	else
837 	  remove(wid);
838       }
839       // restore
840       for (int j=0;j<curs;++j){
841 	Fl_Widget * wid = restore_history_map(cur[j],undo_position);
842 	if (wid)
843 	  add(wid);
844       }
845       resize();
846       in_modified();
847     }
848   }
849 
backup()850   void History_Pack::backup(){
851     // save widget disposition
852     vector<Fl_Widget *> current;
853     int n=children();
854     // cerr << n << " ";
855     for (int i=0;i<n;++i){
856       current.push_back(child(i));
857       // cerr << child(i) << " ";
858     }
859     // cerr << '\n';
860     int us=undo_history.size();
861     if (us>undo_position)
862       undo_history.erase(undo_history.begin()+undo_position,undo_history.end());
863     undo_history.push_back(current);
864     ++undo_position;
865   }
866 
modified(bool do_backup)867   void History_Pack::modified(bool do_backup){
868     if (do_backup)
869       backup();
870     in_modified();
871   }
872 
in_modified()873   void History_Pack::in_modified(){
874     // if (_modified) return;
875     _modified = true ;
876     if (History_Fold * f = get_history_fold(this)){
877       if (f->fold_button){
878 	f->fold_button->color(Xcas_save_unsaved_color);
879 	f->fold_button->redraw();
880       }
881       if (f->save_button){
882 	f->save_button->color(Xcas_save_unsaved_color);
883 	f->save_button->redraw();
884       }
885       f->pack->_modified=true;
886       Fl_Widget * w = f->parent();
887       if (History_Pack * f=dynamic_cast<History_Pack *>(w)){
888 	f->modified(false);
889 	// parent_redraw(f);
890       }
891       return ;
892     }
893     Fl_Group * g = parent();
894     if (!g)
895       return;
896     g=parent_skip_scroll(g);
897     if (!g)
898       return;
899     if (History_Pack * f=dynamic_cast<History_Pack *>(g->parent())){
900       f->modified(false);
901       parent_redraw(f);
902       return ;
903     }
904   }
905 
fold_selection()906   void History_Pack::fold_selection(){
907     int n=children();
908     if (_sel_begin<0 || _sel_end<0 || n<=0 )
909       return;
910     // Get widget at position _sel_begin to have dimensions
911     int s1=min(min(_sel_begin,_sel_end),n-1);
912     int s2=min(max(_sel_begin,_sel_end),n-1);
913     Fl_Widget * c =child(s1);
914     Fl_Group::current(this);
915     History_Fold * res = new History_Fold(c->x(),c->y(),c->w(),c->h());
916     res->labelsize(labelsize());
917     res->labelfont(labelfont());
918     change_group_fontsize(res,labelsize());
919     res->pack->_select=_select;
920     res->pack->_insert=_insert;
921     res->pack->new_question=new_question;
922     res->pack->_spacing=_spacing;
923     res->pack->eval=eval;
924     res->pack->_resize_above=true;
925     res->pack->contextptr = contextptr;
926     // Move _sel_begin to _sel_end to res
927     for (int i=s1;i<=s2;++i){
928       Fl_Widget * c = child(s1);
929       c->resize(c->x(),c->y(),res->pack->w()-res->pack->_printlevel_w,c->h());
930       res->pack->add(c);
931     }
932     insert(*res,s1);
933     res->fold();
934     _sel_begin=_sel_end=s1;
935     modified(true);
936     parent_redraw(this);
937   }
938 
flatten()939   void History_Pack::flatten(){
940     int n=children();
941     if (_sel_begin<0 || _sel_end<0 || n<=0 )
942       return;
943     // Flatten all history_fold's starting from the last one
944     int s1=min(min(_sel_begin,_sel_end),n-1);
945     int s2=min(max(_sel_begin,_sel_end),n-1);
946     for (int i=s2;i>=s1;--i){
947       Fl_Widget * w=child(i);
948       if (!w)
949 	continue;
950       History_Fold * f=dynamic_cast<History_Fold *>(w);
951       if (!f)
952 	continue;
953       // Copy all childrens
954       int m=f->pack->children();
955       for (int j=m-1;j>=0;--j){
956 	insert(*f->pack->child(j),i+1);
957       }
958       f->autosave_rm();
959       add_history_map(w,undo_position);
960       remove(*w);
961       delete w;
962     }
963     modified(true);
964     _sel_begin=_sel_end=-1;
965     parent_redraw(this);
966   }
967 
resize()968   bool History_Pack::resize(){
969     char chaine[25]; // enough even for very large numbers!
970     int n=children();
971     Fl_Widget ** a = (Fl_Widget **) array();
972     sprintf(chaine,"%i",n);
973     fl_font(labelfont(),labelsize());
974     _printlevel_w=int(fl_width(chaine))+2;
975     // Find how much space is required horizontally
976     int W=w(),H=0,X=x(),Y=y();
977     for (int i=0;i<n;++i){
978       Fl_Widget * tmp = *(a+i);
979       tmp->labelsize(labelsize());
980       if (Fl_Input_ * fi=dynamic_cast<Fl_Input_ *>(tmp))
981 	fi->textsize(labelsize());
982       if (tmp->visible()){
983 	if (tmp->h()<2)
984 	  tmp->resize(tmp->x(),tmp->y(),tmp->w(),2);
985 	H+=absint(tmp->h())+_spacing;
986 	// W=max(W,tmp->w());
987       }
988     }
989     // H -= _spacing;
990     // New horizontal size is therefore _printlevel_w+W
991     int newh=min(max(H,1),
992 #ifdef _HAVE_FL_UTF8_HDR_
993 		 1<<30
994 #else
995 		 1<<14
996 #endif
997 		 );
998     if (newh<H){
999       cerr << "Too many large widgets. Compressing" << '\n';
1000       double ratio=double(newh)/H;
1001       newh=0;
1002       int y0=y(),hh;
1003       for (int i=0;i<n;++i){
1004 	Fl_Widget * tmp = *(a+i);
1005 	hh=int(tmp->h()*ratio);
1006 	tmp->resize(tmp->x(),y0,tmp->w(),hh);
1007 	y0 += hh;
1008 	newh += hh;
1009       }
1010     }
1011     if (newh==h())
1012       return false;
1013     int oldh=h();
1014     if (_resize_above){ // if(newh>oldh)
1015       // cerr << newh-h() << '\n';
1016       increase_size(this,newh-oldh);
1017     }
1018     else
1019       Fl_Widget::resize(X,Y,W,newh);
1020     bool modif=false;
1021     X=x(); Y=y(); W=w()-_printlevel_w; H=h();
1022     int X1=X+_printlevel_w,Y1=Y;
1023     // check_fl_rectf(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h,0,0);
1024     for (int i=0;i<n;++i){
1025       Fl_Widget * tmp = *(a+i);
1026       if (Fl_Tile * tl = dynamic_cast<Fl_Tile *>(tmp)){
1027 	// check that the first child of tl has non-0 size
1028 	if (tl->children() && tl->child(0)->h()<1){
1029 	  Fl_Widget * tl0=tl->child(0);
1030 	  tl0->resize(tl0->x(),tl0->y(),tl0->w(),1);
1031 	}
1032       }
1033       if ( tmp->x()!=X1 || tmp->y()!=Y1 || tmp->w()!=W ){
1034 	tmp->resize(X1,Y1,W,max(absint(tmp->h()),2));
1035 	modif=true;
1036       }
1037       if (tmp->visible()){
1038 	Y1 += tmp->h()+_spacing;
1039       }
1040     }
1041     if (modif)
1042       init_sizes();
1043     if (!doing_eval)
1044       parent_redraw(this);
1045     // cerr << "resize " << this << " " << newh << " " << h() << " " << int(damage()) << '\n';
1046     return true;
1047   }
1048 
resize(int maxh)1049   bool History_Pack::resize(int maxh){
1050     int n=children();
1051     for (int i=0;i<n;++i){
1052       Fl_Widget * wid = child(i);
1053       if (wid->h()>maxh)
1054 	wid->resize(wid->x(),wid->y(),wid->w(),maxh);
1055     }
1056     return resize();
1057   }
1058 
resize(int minh,int maxh)1059   bool History_Pack::resize(int minh,int maxh){
1060     int n=children();
1061     for (int i=0;i<n;++i){
1062       Fl_Widget * wid = child(i);
1063       if (wid->h()<minh)
1064 	wid->resize(wid->x(),wid->y(),wid->w(),minh);
1065       if (wid->h()>maxh)
1066 	wid->resize(wid->x(),wid->y(),wid->w(),maxh);
1067     }
1068     return resize();
1069   }
1070 
1071   // This call is required for embedded subwindows to be hidden or shown
1072   // because they do not use the clipping mechanism of usual widgets
hide_show_windows(const Fl_Group * g,int cx,int cy,int cw,int ch)1073   void hide_show_windows(const Fl_Group * g,int cx,int cy,int cw,int ch){
1074     int n=g->children();
1075     Fl_Widget ** a = (Fl_Widget **) g->array();
1076     for (int i=0;i<n;++i,++a){
1077       Fl_Widget * tmp = *a;
1078       if (Fl_Window * win = dynamic_cast<Fl_Window *>(tmp)){
1079 	cerr << win->x()<< " " << cx << " " << win->y()<< " " << cy << " " << win->w() << " " << cw << " " << win->h() << " " << ch << '\n';
1080 	if (win->x()<cx || win->y()<cy || win->x()+win->w() >cx+cw || win->y()+win->h() >cy+ch )
1081 	  win->hide();
1082 	else {
1083 	  win->show();
1084 	  win->redraw();
1085 	}
1086 	continue;
1087       }
1088       if (Fl_Group * gr = dynamic_cast<Fl_Group *>(tmp)){
1089 	hide_show_windows(gr,cx,cy,cw,ch);
1090       }
1091     }
1092   }
1093 
draw()1094   void History_Pack::draw(){
1095     resize();
1096     int clip_x,clip_y,clip_w,clip_h;
1097     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
1098     if (!clip_w || !clip_h)
1099       return;
1100     // cerr << this << " " << x() << " " << y() << " " << w() << " " << h() << " " << clip_x << " " << clip_y << " " << clip_w << " " << clip_h << " " << int(damage()) << '\n';
1101     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
1102     // does not work...
1103     // hide_show_windows(this,clip_x,clip_y,clip_w,clip_h);
1104     // if (window()) window()->show();
1105     fl_font(labelfont(),labelsize());
1106     char chaine[25]; // enough even for very large numbers!
1107     int n=children();
1108     Fl_Widget ** a = (Fl_Widget **) array();
1109     int X=x(),Y=y(),W=w()-_printlevel_w,H=h(),X1=X+_printlevel_w,Y1=Y;
1110     // Replace widgets if necessary and redraw spacings
1111     bool modif=false;
1112     fl_color(color());
1113     // check_fl_rectf(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h,0,0);
1114     for (int i=0;i<n;++i){
1115       Fl_Widget * tmp = *(a+i);
1116       if ( tmp->x()!=X1 || tmp->y()!=Y1 || tmp->w()!=W ){
1117 	tmp->resize(X1,Y1,W,max(absint(tmp->h()),1));
1118 	modif=true;
1119 	// if (tmp->visible() && parent()) parent()->redraw();
1120       }
1121       if (tmp->visible()){
1122 	// tmp->redraw();
1123 	Y1 += tmp->h()+_spacing;
1124       }
1125     }
1126     if (modif){
1127       // cerr << "init_sizes" << '\n';
1128       init_sizes();
1129     }
1130     // Redraw widgets
1131     Fl_Group::draw();
1132     // Draw spacings
1133     // Print history level numbers
1134     X=x()+1; Y=y(); Y1=Y; W=w()-_printlevel_w;H=h();
1135     fl_font(labelfont(),labelsize());
1136     fl_color(color());
1137     check_fl_rectf(x(),y(),_printlevel_w,H,clip_x,clip_y,clip_w,clip_h,0,0);
1138     int l=labelsize()+labeladd,m=min(_sel_begin,_sel_end),M=max(_sel_begin,_sel_end);
1139     for (int i=0;i<n;++i,++a){
1140       Fl_Widget * tmp = *a;
1141       if (tmp->visible()){
1142 	sprintf(chaine,"%i",i+1);
1143 	int j=(*a)->y();
1144 	bool inverse ;
1145 	inverse = m>=0 && i>=m && i<=M ;
1146 	if (inverse)
1147 	  fl_color(FL_BLACK);
1148 	else
1149 	  fl_color(FL_WHITE);
1150 	// if (fl_not_clipped(X, j, _printlevel_w, l)){
1151 	  fl_rectf(X,j,_printlevel_w,l);
1152 	  // check_fl_rectf(X,j,_printlevel_w,l,clip_x,clip_y,clip_w,clip_h,0,0);
1153 	  if (inverse)
1154 	    fl_color(FL_WHITE);
1155 	  else
1156 	    fl_color(FL_BLACK);
1157 	  fl_rect(X,j,_printlevel_w,l);
1158 	  // check_fl_rect(X,j,_printlevel_w,l,clip_x,clip_y,clip_w,clip_h,0,0);
1159 	  fl_draw(chaine,X+1,j+l-labeladd/2-1);
1160 	  // check_fl_draw(chaine,X+2,j+l-labeladd/2-1,clip_x,clip_y,clip_w,clip_h,0,0);
1161 	  // }
1162 	// redraw spacing
1163 	if (_spacing){
1164 	  Y1 += (*a)->h();
1165 	  fl_color(FL_BLACK);
1166 	  check_fl_line(X,Y1+1,X+w(),Y1+1,clip_x,clip_y,clip_w,clip_h,0,0);
1167 	  check_fl_line(X,Y1+_spacing-1,X+w(),Y1+_spacing-1,clip_x,clip_y,clip_w,clip_h,0,0);
1168 	  Y1 += _spacing;
1169 	  fl_color(color());
1170 	}
1171       }
1172     }
1173     fl_pop_clip();
1174   }
1175 
1176 
1177 
1178   // From Fl_Tile.cxx
set_cursor(Fl_Widget * t,Fl_Cursor c)1179   void set_cursor(Fl_Widget *t, Fl_Cursor c) {
1180     static Fl_Cursor cursor;
1181     if (cursor == c || !t->window()) return;
1182     cursor = c;
1183 #ifdef __sgi
1184     t->window()->cursor(c,FL_RED,FL_WHITE);
1185 #else
1186     t->window()->cursor(c);
1187 #endif
1188   }
1189 
1190   static Fl_Cursor cursors[4] = {
1191     FL_CURSOR_DEFAULT,
1192     FL_CURSOR_WE,
1193     FL_CURSOR_NS,
1194     FL_CURSOR_MOVE
1195   };
1196 
handle(int event)1197   int History_Pack::handle(int event){
1198     if (event==FL_MOUSEWHEEL){
1199 #if 1
1200       if (!Fl::event_inside(this)) return 0;
1201       return Fl_Group::handle(event);
1202       for (unsigned i=0;i<children();i++){
1203 	int res=child(i)->handle(event);
1204 	if (res)
1205 	  return res;
1206       }
1207       return 0;
1208 #else
1209       return 0;
1210 #endif
1211     }
1212     if (event==FL_FOCUS){
1213       return Fl_Group::handle(event);
1214     }
1215     if (event==FL_UNFOCUS){
1216       // _sel_end = _sel_begin = -1;
1217       // this prevents middle mouse insertion
1218       return Fl_Group::handle(event);
1219     }
1220     if (event==FL_KEYBOARD){
1221       if (Fl::event_alt() && Fl::event_key()){
1222 	if (Fl_Window * w=window()){
1223 	  int n=w->children();
1224 	  for (int i=0;i<n;++i){
1225 	    if (Fl_Menu_Bar * mb=dynamic_cast<Fl_Menu_Bar *>(w->child(i)))
1226 	      return mb->handle(FL_SHORTCUT);
1227 	  }
1228 	}
1229       }
1230       if (Fl::event_key()==FL_BackSpace || Fl::event_key()==FL_Delete){
1231 	remove_selected_levels(false);
1232 	return 1;
1233       }
1234       char ch=Fl::event_text()?Fl::event_text()[0]:0;
1235       if (ch==17 && !children()){ // Ctrl-Q -> search for a main menu shortcut
1236 	if (Fl_Window * w=window()){
1237 	  int n=w->children();
1238 	  for (int i=0;i<n;++i){
1239 	    if (Fl_Menu_Bar * mb=dynamic_cast<Fl_Menu_Bar *>(w->child(i)))
1240 	      return mb->handle(FL_SHORTCUT);
1241 	  }
1242 	}
1243       }
1244       if (ch==3 || ch==24){ // Ctrl-C
1245 	if (_select){
1246 	  const char * ch=_select(this,_sel_begin,_sel_end);
1247 	  Fl::copy(ch,strlen(ch),1);
1248 	}
1249 	if (ch==24)
1250 	  remove_selected_levels(false);
1251 	return 1;
1252       }
1253       if (ch==22){ // Ctrl-V
1254 	Fl::paste(*this, 1);
1255 	return 1;
1256       }
1257       if (ch==25){
1258 	History_cb_Redo(this,0);
1259 	return 1;
1260       }
1261       if (ch==26){
1262 	History_cb_Undo(this,0);
1263 	return 1;
1264       }
1265     }
1266     if (Fl::event_button()== FL_MIDDLE_MOUSE ){
1267       if (event==FL_RELEASE){
1268 	Fl::paste(*this);
1269 	_selecting = _moving = _pushed = false;
1270 	return 1;
1271       }
1272     }
1273     if (event==FL_PASTE){
1274       if (!_insert)
1275 	return 0;
1276       _insert(this,Fl::event_text(),-1,_sel_begin);
1277       _sel_begin = _sel_end = -1;
1278       update(); // commented
1279       parent_redraw(this);
1280       return 1;
1281     }
1282     int mx = Fl::event_x();
1283     int my = Fl::event_y();
1284     if (event==FL_DRAG){
1285       if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(parent())){
1286 	int mousey=my-y(),Y=s->yposition(),dh=h()-s->h();
1287 	if (mousey>Y+s->h() && dh>Y)
1288 #ifdef _HAVE_FL_UTF8_HDR_
1289 	  s->scroll_to(s->xposition(),min(mousey-s->h(),dh));
1290 #else
1291 	  s->position(s->xposition(),min(mousey-s->h(),dh));
1292 #endif
1293 	if (mousey<Y && Y>0)
1294 #ifdef _HAVE_FL_UTF8_HDR_
1295 	  s->scroll_to(s->xposition(),max(0,mousey));
1296 #else
1297 	  s->position(s->xposition(),max(0,mousey));
1298 #endif
1299       }
1300     }
1301     int n=children();
1302     if (!n)
1303       return 0;
1304     Fl_Widget*const* a = array();
1305     if (_selecting){
1306       switch(event){
1307       case FL_RELEASE:
1308 	_selecting = false;
1309 	_moving = _pushed = false;
1310       case FL_DRAG:
1311 	if (!Fl::event_state(FL_SHIFT)){
1312 	  int old_sel_end=_sel_end;
1313 	  if (my<(*a)->y()){
1314 	    _sel_end=0;
1315 	  }
1316 	  else {
1317 	    int i;
1318 	    for (i=0; i<n;i++ ) {
1319 	      Fl_Widget* o = *(a+i);
1320 	      int yh=o->y();
1321 	      if ( my >= yh && my < yh + o->h() + _spacing )
1322 		break;
1323 	    }
1324 	    _sel_end=i;
1325 	  }
1326 	  if (old_sel_end!=_sel_end)
1327 	    damage(1);
1328 	}
1329 	if (_select && event==FL_RELEASE){
1330 	  const char * ch=_select(this,_sel_begin,_sel_end);
1331 	  if (ch) Fl::selection(*this,ch,strlen(ch));
1332 	}
1333 	break;
1334       } // end switch
1335       return 1;
1336     }
1337     if (_moving){
1338       if (event==FL_RELEASE){
1339 	_selecting = false;
1340 	_moving = _pushed = false;
1341 	// Check if final position is in current History_Pack
1342 	if (mx>=x() && mx <= x()+w()){
1343 	  int i;
1344 	  for (i=0; i<n;i++ ) {
1345 	    Fl_Widget* o = *(a+i);
1346 	    int yh=o->y();
1347 	    bool truehf=false;
1348 	    if (History_Fold * hf=dynamic_cast<History_Fold*>(o))
1349 	      truehf=hf->pack->_resize_above; // hf->group->visible() doesn't work
1350 	    if ( my >= yh && my < yh + o->h() && !truehf){
1351 	      // Move _sel_begin to _sel_end after i (if i>_sel_end)
1352 	      // before i (if i<_sel_begin)
1353 	      set_cursor(this, FL_CURSOR_ARROW);
1354 	      int m=min(_sel_begin,_sel_end),M=max(_sel_begin,_sel_end);
1355 	      if (i<=M && i>=m) return 1;
1356 	      if (i>M){
1357 		for (;M>=m;--M)
1358 		  insert(*child(m),i+1);
1359 	      }
1360 	      else {
1361 		for (;m<=M;++m)
1362 		  insert(*child(M),i);
1363 	      }
1364 	      update();
1365 	      _sel_end = _sel_begin=-1;
1366 	      modified(true);
1367 	      redraw();
1368 	      return 1;
1369 	    }
1370 	  } // end for
1371 	} // end if mx...
1372 	// try to find an History_Pack above mx,my
1373 	// using parent() to go up and child() to go down
1374 	Fl_Widget * o = this;
1375 	for (;o;){
1376 	  if (mx>=o->x() && mx<=o->x()+o->w() && my>=o->y() && my<=o->y()+o->h())
1377 	    break;
1378 	  o=o->parent();
1379 	}
1380 	if (!o)
1381 	  return 1;
1382 	// release on a tab?
1383 	if (Fl_Tabs * tab=dynamic_cast<Fl_Tabs *>(o)){
1384 	  o=tab->which(mx,my);
1385 	  if (History_Fold * hf=dynamic_cast<History_Fold *>(o)){
1386 	    hf->pack->_sel_begin=-1;
1387 	    Fl::paste(*hf->pack);
1388 	    return 1;
1389 	  }
1390 	}
1391 	// go down to find an History_Pack with
1392 	Fl_Group * g = dynamic_cast<Fl_Group *>(o);
1393 	o=0;
1394 	History_Pack * h=dynamic_cast<History_Pack *>(g);
1395 	bool set_i=h;
1396 	int i_=-1;
1397 	for (;g;){
1398 	  int n=g->children(),i;
1399 	  for (i=0;i<n;++i){
1400 	    // Stop at first children found
1401 	    o=g->child(i);
1402 	    if (mx>=o->x() && mx<=o->x()+o->w() && my>=o->y() && my<=o->y()+o->h())
1403 	      break;
1404 	  }
1405 	  // No children found, stop the search
1406 	  if (i==n)
1407 	    break;
1408 	  if (set_i)
1409 	    i_=i;
1410 	  if (History_Pack * hp=dynamic_cast<History_Pack *>(o)){
1411 	    h=hp;
1412 	    set_i=true;
1413 	  }
1414 	  else {
1415 	    if (History_Fold * hf=dynamic_cast<History_Fold *>(o)){
1416 	      h=hf->pack;
1417 	      set_i=true;
1418 	    }
1419 	    else
1420 	      set_i=false;
1421 	  }
1422 	  // Not an history pack, try again
1423 	  g=dynamic_cast<Fl_Group *>(o);
1424 	}
1425 	if (h && h!=this){
1426 	  h->_sel_begin=i_;
1427 	  Fl::paste(*h);
1428 	}
1429 	return 1;
1430       } // end if event==FL_RELEASE
1431       return 1;
1432     } // end if (_moving)
1433     if (!_pushed && mx>=x() && mx<x()+_printlevel_w-1){
1434       if (event==FL_MOVE){
1435 	for (int i=0; i<n;i++ ) {
1436 	  Fl_Widget* o = *(a+i);
1437 	  int yh=o->y();
1438 	  if ( my >= yh && my < yh + o->h() ) {
1439 	    if (my<yh+labelsize())
1440 	      set_cursor(this,FL_CURSOR_HAND);
1441 	    else
1442 	      set_cursor(this,FL_CURSOR_ARROW);
1443 	    return 1;
1444 	  }
1445 	}
1446       }
1447       if (event==FL_PUSH){
1448 	if (Fl::focus()!=this)
1449 	  Fl::focus(this);
1450 	_selecting = _moving = _pushed = false;
1451 	if (Fl::event_button()== FL_MIDDLE_MOUSE ){
1452 	  for (int i=0; i<n;i++ ) {
1453 	    Fl_Widget* o = *(a+i);
1454 	    int yh=o->y();
1455 	    if ( my >= yh && my < yh + o->h() ) {
1456 	      _sel_begin = _sel_end = i;
1457 	    }
1458 	  }
1459 	  return 1;
1460 	}
1461 	_selecting=true;
1462 	for (int i=0; i<n;i++ ) {
1463 	  Fl_Widget* o = *(a+i);
1464 	  int yh=o->y();
1465 	  if ( my >= yh && my < yh + o->h() ) {
1466 	    // If i is between _sel_begin and _sel_end, move
1467 	    int m=min(_sel_begin,_sel_end),M=max(_sel_begin,_sel_end);
1468 	    if (m==-1 && M ==-1 && my<yh+labelsize())
1469 	      m = M = _sel_begin = _sel_end = i;
1470 	    if (m>-1 && m<=i && i<=M){
1471 	      _moving=true;
1472 	      _selecting = false;
1473 	      if (_select){
1474 		const char * ch=_select(this,_sel_begin,_sel_end);
1475 		if (ch) Fl::selection(*this,ch,strlen(ch));
1476 	      }
1477 	      set_cursor(this,FL_CURSOR_MOVE);
1478 	    }
1479 	    else {
1480 	      if(Fl::event_state(FL_SHIFT)){
1481 		if (i<m){
1482 		  _sel_begin=i;
1483 		  _sel_end=M;
1484 		}
1485 		else {
1486 		  if (i>M){
1487 		    _sel_begin=m;
1488 		    _sel_end=i;
1489 		  }
1490 		}
1491 	      }
1492 	      else {
1493 		_sel_begin=i;
1494 		_sel_end=i;
1495 	      }
1496 	    }
1497 	    damage(1);
1498 	    return 1;
1499 	  } // end if (my >= yh && my < yh + o->h())
1500 	}
1501       }
1502       set_cursor(this, FL_CURSOR_ARROW);
1503       return 1;
1504     }
1505     else {
1506       switch (event) {
1507       case FL_MOVE:
1508       case FL_ENTER:
1509       case FL_PUSH:
1510 	{
1511 	  _moving = _selecting = false;
1512 	  _pushed = event==FL_PUSH;
1513 	  if (_pushed){
1514 	    _sel_end = _sel_begin = -1;
1515 	    damage(1);
1516 	  }
1517 	  for (int i=0; i<n;i++ ) {
1518 	    Fl_Widget* o = *(a+i);
1519 	    int yh=o->y()+o->h();
1520 	    if ( yh <= my+GRABAREA && yh >= my-GRABAREA ) {
1521 	      _my_push=my;
1522 	      _widget_i=i;
1523 	      _widget_h=o->h();
1524 	      if (_pushed) modified(true);
1525 	      set_cursor(this, cursors[2]);
1526 	      return 1;
1527 	    }
1528 	  }
1529 	  _pushed = false;
1530 	  set_cursor(this, FL_CURSOR_DEFAULT);
1531 	  return Fl_Group::handle(event);
1532 	}
1533       case FL_LEAVE:
1534 	set_cursor(this, FL_CURSOR_DEFAULT);
1535 	_moving = _pushed = false;
1536 	break;
1537       case FL_DRAG:
1538       case FL_RELEASE:
1539 	if (_pushed){
1540 	  Fl_Widget * o = child(_widget_i);
1541 	  HScroll * hs = dynamic_cast<HScroll *>(parent());
1542 	  int oldh=o->h();
1543 	  int newh=max(_widget_h+my-_my_push,10);
1544 	  if (hs && hs->resizechildren && _widget_i+1<children()){
1545 	    Fl_Widget * nexto=child(_widget_i+1);
1546 	    int nextnewh=nexto->h()+oldh-newh;
1547 	    if (nextnewh<10){
1548 	      newh -= (10-nextnewh);
1549 	      nextnewh=10;
1550 	    }
1551 	    nexto->resize(o->x(),o->y()+o->h(),nexto->w(),nextnewh);
1552 	  }
1553 	  if (!hs || (hs->resizechildren && _widget_i+1<children() )){
1554 	    o->resize(o->x(),o->y(),o->w(),max(newh,1));
1555 	    parent_redraw(this);
1556 	  }
1557 	  _pushed = event!=FL_RELEASE ;
1558 	  _moving = _selecting = false ;
1559 	  return 1;
1560 	}
1561       } // end switch
1562     } // end if !_pushed && mx<labelsize()
1563     return Fl_Group::handle(event);
1564   }
1565 
save(const char * ch)1566   bool History_Pack::save(const char * ch){
1567     if (!_modified && !url)
1568       return false;
1569     if (url)
1570       return save_as(url->c_str(),ch,true,true,file_save_context);
1571     else
1572       return save_as(ch);
1573   }
1574 
autosave(bool warn_user)1575   bool History_Fold::autosave(bool warn_user){
1576     if (!pack->_modified || (input && input->visible()))
1577       return false;
1578     if (debug_infolevel)
1579       cerr << "Autosaving " << autosave_filename << '\n';
1580     bool res=pack->save_as(autosave_filename.c_str(),0,false,warn_user,false);
1581     pack->modified(false);
1582     return res;
1583   }
1584 
confirm_close(const string & message)1585   int confirm_close(const string & message){
1586     int i=fl_choice("%s",gettext("Cancel"),gettext("Yes"),gettext("No"),message.c_str());
1587     return i;
1588   }
1589 
close(const char * ch)1590   bool History_Pack::close(const char * ch){
1591     if (_modified){
1592       int i=confirm_close(string(ch)+gettext(" modified. Save?"));
1593       if (!i)
1594 	return false;
1595       if (i==1){
1596 	if (!save(ch))
1597 	  return false;
1598       }
1599     }
1600     clear();
1601     Fl_Group * w =parent();
1602     if (w){
1603       w->remove(this);
1604       parent_redraw(w);
1605     }
1606     if (logstream){
1607       delete logstream;
1608       logstream=0;
1609     }
1610     return true;
1611   }
1612 
save_all()1613   bool History_Pack::save_all(){
1614     int n=children();
1615     for (int i=0;i<n;++i){
1616       if (History_Fold * f=dynamic_cast<History_Fold *>(child(i))){
1617 	if (f->pack->_modified){
1618 	  char chaine[25]; // enough even for very large numbers!
1619 	  sprintf(chaine,"%i",i+1);
1620 	  string name="session "+string(chaine)+" ";
1621 	  if (f->pack->url)
1622 	    name += *f->pack->url ;
1623 	  int j=confirm_close((name+gettext(" has changed. Save?")).c_str());
1624 	  if (j==0)
1625 	    return false;
1626 	  if (j!=2)
1627 	    f->pack->save(name.c_str());
1628 	  else
1629 	    f->pack->clear_modified();
1630 	  f->autosave_rm();
1631 	}
1632       }
1633     }
1634     return true;
1635   }
1636 
1637 #ifdef WIN32
unix_path(const std::string & winpath)1638   std::string unix_path(const std::string & winpath){
1639 #ifdef x86_64
1640     int s = cygwin_conv_path (CCP_WIN_A_TO_POSIX , winpath.c_str(), NULL, 0);
1641     char * unixpath = (char *) malloc(s);
1642     cygwin_conv_path(CCP_WIN_A_TO_POSIX,winpath.c_str(), unixpath,s);
1643 #else
1644     char * unixpath = (char *) malloc (cygwin_win32_to_posix_path_list_buf_size (winpath.c_str()));
1645     cygwin_win32_to_posix_path_list (winpath.c_str(), unixpath);
1646 #endif
1647     string res=unixpath;
1648     free(unixpath);
1649     return res;
1650   }
1651 #else
1652 
unix_path(const std::string & winpath)1653   std::string unix_path(const std::string & winpath){
1654     return winpath;
1655   }
1656 
1657 #endif
1658 
new_url(const char * newfile)1659   void History_Pack::new_url(const char * newfile){
1660     if (url)
1661       delete url;
1662     string newf=newfile;
1663     char buf[1024];
1664     if (getcwd(buf,1023)){
1665       string newf1=remove_path(newfile);
1666       if (buf+('/'+newf1)==newf)
1667 	newf=newf1;
1668     }
1669     url = new string(unix_path(newf));
1670     if (History_Fold * hf=get_history_fold(this)){
1671       hf->label(url->c_str());
1672       if (hf->parent())
1673 	hf->parent()->redraw();
1674     }
1675   }
1676 
save_as(const char * ch)1677   bool History_Pack::save_as(const char * ch){
1678     if (!_select)
1679       return false;
1680     Fl_Widget * wid = xcas::Xcas_input_focus;
1681     // get filename
1682     string tmp="Save worksheet ";
1683     if (ch)
1684       tmp += ch;
1685     string fname;
1686     if (url)
1687       fname=remove_path(remove_extension(*url))+"_.xws";
1688     else
1689       fname="session.xws";
1690     char * newfile = file_chooser(tmp.c_str(), "*.xws", fname.c_str());
1691     if (wid)
1692       Fl::focus(wid);
1693     // check filename
1694     if ( !newfile )
1695       return false;
1696 #if 1 // ndef WIN32
1697     string sn=get_path(unix_path(newfile));
1698     if (!sn.empty()){
1699 #ifndef HAVE_NO_CWD
1700       // _cd(string2gen(sn,false),contextptr);
1701       chdir(sn.c_str());
1702 #endif
1703     }
1704 #endif
1705     string s=remove_extension(newfile)+".xws";
1706     if (is_file_available(s.c_str())){
1707       int i=fl_ask("%s",("File "+s+" exists. Overwrite?").c_str());
1708       if ( !i )
1709 	return false;
1710     }
1711     // Save filename
1712     new_url(s.c_str());
1713     return save_as(s.c_str(),ch,true,true,file_save_context);
1714   }
1715 
save_as(const char * filename,const char * ch,bool autosave_rm,bool warn_user,bool savecontext)1716   bool History_Pack::save_as(const char * filename,const char * ch,bool autosave_rm,bool warn_user,bool savecontext){
1717     if (!filename || !_select || _saving)
1718       return false;
1719     static string html5;
1720     html5=widget_html5(this);
1721     if (autosave_rm) Fl::copy(html5.c_str(),html5.size(),1);
1722     const char * chs=_select(this,0,children()-1);
1723     if (!chs)
1724       return false;
1725     _saving = true;
1726     FILE * f(fopen(filename,"w"));
1727     if (!f){
1728       string message=string(gettext("Unable to open file "))+filename;
1729       if (warn_user)
1730 	fl_alert("%s",message.c_str());
1731       cerr << message << '\n';
1732       if (url){
1733 	delete url;
1734 	url=0;
1735       }
1736       if (History_Fold * hf=get_history_fold(this)){
1737 	hf->label(gettext("Unnamed"));
1738       }
1739       _saving = false;
1740       return false;
1741     }
1742     if (recent_filenames_menu)
1743       add_recent_filename(filename,true);
1744     int savepos=_sel_begin,pos,yscrollerpos;
1745     Fl_Scroll * scroller = dynamic_cast<Fl_Scroll *>(parent());
1746     if (scroller)
1747       yscrollerpos=scroller->yposition();
1748     pos=focus(Xcas_input_focus);
1749     if (pos==-1)
1750       pos=_sel_begin;
1751     bool usepos=false,dbg=false;
1752     if (xcas::Xcas_Debug_Window && xcas::Xcas_Debug_Window->shown())
1753       dbg=true;
1754     if (pos<0)
1755       pos=update_pos;
1756     else
1757       usepos=(dynamic_cast<Equation *>(Xcas_input_focus)==0);
1758     _sel_begin=savepos;
1759     fprintf(f,"// xcas version=%s fontsize=%i font=%i currentlevel=%i pixon=%i\n",VERSION,labelsize(),labelfont(),pos,pixon_size);
1760     fprintf(f,"%s",chs);
1761     if (savecontext){
1762       string tmps=archive_session(false,contextptr);
1763       fprintf(f,"// context ");
1764       int L=tmps.size();
1765       fprintf(f,"%i ",L);
1766       for (int i=0;i<L;++i){
1767 	fprintf(f,"%c",tmps[i]);
1768       }
1769       fprintf(f,"\n");
1770     }
1771     fclose(f);
1772     _saving = false;
1773     clear_modified();
1774     if (autosave_rm){
1775       if (History_Fold * hf=dynamic_cast<History_Fold *>(parent_skip_scroll(this)))
1776 	hf->autosave_rm();
1777     }
1778     if (!usepos && Xcas_input_focus){
1779       Fl::focus(Xcas_input_focus);
1780       if (Fl_Input_ * ptr=dynamic_cast<Fl_Input_*>(Xcas_input_focus))
1781 	ptr->position(ptr->position(),ptr->position());
1782     }
1783     else {
1784       focus(pos,true);
1785       if (Fl_Input_ * ptr=dynamic_cast<Fl_Input_*>(Fl::focus()))
1786 	ptr->position(ptr->position(),ptr->position());
1787     }
1788     if (dbg)
1789       Fl::focus(xcas::Xcas_Debug_Window);
1790     if (scroller){
1791 #ifdef _HAVE_FL_UTF8_HDR_
1792       scroller->scroll_to(0,yscrollerpos);
1793 #else
1794       scroller->position(0,yscrollerpos);
1795 #endif
1796     }
1797     return true;
1798   }
1799 
count(const char * ch,char c)1800   int count(const char * ch,char c){
1801     int res=0;
1802     for (;*ch;++ch){
1803       if (*ch==c)
1804 	++res;
1805     }
1806     return res;
1807   }
1808 
casio2xws(const char * s,int ss,int l,GIAC_CONTEXT)1809   string casio2xws(const char * s,int ss,int l,GIAC_CONTEXT){
1810     int pos=0;
1811 #if 0
1812     ofstream of("log.xws");
1813 #else
1814 #ifdef HAVE_SSTREAM
1815     ostringstream of;
1816 #else
1817     ostrstream of;
1818 #endif
1819 #endif
1820     int x=49,y=87,w=626,h=l+1;
1821     unsigned const char * ptr=(unsigned const char*)s;
1822     int L=((ptr[0]*256+ptr[1])*256+ptr[2])*256+ptr[3]; ptr+=4; pos+=4;
1823     char buf_mode[L+1];
1824     strncpy(buf_mode,(const char *)ptr,L); ptr+=L; pos+=L;
1825     buf_mode[L]=0;
1826 #if 1
1827     python_compat(0,contextptr);
1828     gen vars(buf_mode,contextptr);
1829     vars=eval(vars,1,contextptr);
1830 #else
1831     int dh=5+h*(1+count(buf_mode,'\n'));
1832     of << "// fltk 7Fl_Tile " << x << " " << y << " "<< w << " " << dh << '\n';
1833     of << "[" << '\n';
1834     of << "// fltk N4xcas16Xcas_Text_EditorE "<< x << " " << y << " "<< w << " " << dh << " " << h << " " << 0 << '\n';
1835     y += dh;
1836     of << L << " ," << '\n' << buf_mode << "," << '\n' << "]\n,\n";
1837 #endif
1838     L=((ptr[0]*256+ptr[1])*256+ptr[2])*256+ptr[3]; ptr+=4;
1839     char buf_script[L+1];
1840     strncpy(buf_script,(const char *)ptr,L); ptr+=L; pos+=L;
1841     buf_script[L]=0;
1842     int dh=50+h*(1+count(buf_script,'\n'));
1843     of << "// fltk 7Fl_Tile " << x << " " << y << " "<< w << " " << dh << '\n';
1844     of << "[" << '\n';
1845     of << "// fltk N4Xcas7EditeurE "<< x << " " << y << " "<< w << " " << dh << " " << h << " " << 0 << '\n';
1846     of << L << " ," << '\n' << buf_script << "," <<'\n' << "]\n,\n";
1847     y += dh;
1848     for (;pos<ss;){
1849       L=ptr[0]*256+ptr[1]; ptr+=2; pos+=2;
1850       if (L==0) break;
1851       // ptr[0],ptr[1] cursor position ignored
1852       int type=ptr[2]; ptr+=4; pos+=4;
1853       char buf_[L+1];
1854       char * buf=buf_;
1855       strncpy(buf,(const char *)ptr,L); ptr+=L; pos+=L;
1856       buf[L]=0;
1857       dh=5+h*(1+count(buf,'\n'));
1858       bool comment=false;
1859       if (L>=2){
1860 	if (buf[0]=='#'){
1861 	  comment=true;
1862 	  buf++;
1863 	  L--;
1864 	}
1865 	if (!comment && buf[0]=='/') {
1866 	  if (buf[1]=='/'){
1867 	    comment=true;
1868 	    buf++;
1869 	    L-=2;
1870 	  }
1871 	  else {
1872 	    if (buf[1]=='*'){
1873 	      string s(string(buf).substr(2,L-4));
1874 	      strcpy(buf,s.c_str());
1875 	      comment=true;
1876 	      L-=4;
1877 	    }
1878 	  }
1879 	}
1880       }
1881       if (type==0){
1882 	of << "// fltk 7Fl_Tile " << x << " " << y << " "<< w << " " << dh << '\n';
1883 	of << "[" << '\n';
1884 	of << (comment?"// fltk N4xcas23Comment_Multiline_InputE ":"// fltk N4xcas16Xcas_Text_EditorE ")<< x << " " << y << " "<< w << " " << dh << " " << h << " " << 0 << '\n';
1885 	if (comment)
1886 	  of << replace(buf,'\n','�');
1887 	else
1888 	  of << L << " ," << '\n' << buf << "," ;
1889 	of << '\n' << "]\n,\n";
1890 	y += dh;
1891       }
1892     }
1893 #if 0
1894     return "";
1895 #else
1896     return of.str();
1897 #endif
1898   }
1899 
1900   // Maple worksheet translate, returns new y position
mws2xws(istream & inf,ostream & of,int x,int y,int w,int h)1901   int mws2xws(istream & inf,ostream & of,int x,int y,int w,int h){
1902     string mapletxt;
1903     while (inf && of && !inf.eof()){
1904       inf >> mapletxt;
1905       int n1,n2,n3;
1906       n1=mapletxt.size();
1907       if (n1>7 && mapletxt.substr(n1-7,7)=="MPLTEXT"){
1908         inf >> n1 >> n2 >> n3; // n1=1? n2=0? n3=length
1909 #ifdef HAVE_SSTREAM
1910 	ostringstream os;
1911 #else
1912 	ostrstream os;
1913 #endif
1914 	in_mws_translate(inf,os);
1915 	int dh=5+h*(1+count(string(os.str()).c_str(),'\n'));
1916 	of << "// fltk 7Fl_Tile " << x << " " << y << " "<< w << " " << dh << '\n';
1917 	of << "[" << '\n';
1918 	of << "// fltk maple_Multiline_Input_tab "<< x << " " << y << " "<< w << " " << dh << '\n';
1919 	y += dh;
1920 	of << replace(os.str(),'\n','�');
1921 	of << "\n,\n]\n";
1922       }
1923       else {
1924 	if ( (n1>4 && mapletxt.substr(n1-4,4)=="TEXT") || (n1>7 && mapletxt.substr(n1-7,7)=="XPPEDIT") ){
1925 	  inf >> n1 >> n2;
1926 #ifdef HAVE_SSTREAM
1927 	  ostringstream os;
1928 #else
1929 	  ostrstream os;
1930 #endif
1931 	  in_mws_translate(inf,os);
1932 	  int dh=5+h*(1+count(string(os.str()).c_str(),'\n'));
1933 	  of << "// fltk 7Fl_Tile " << x << " " << y << " "<< w << " " << dh << '\n';
1934 	  of << "[" << '\n';
1935 	  of << "// fltk maple_Multiline_Input "<< x << " " << y << " "<< w << " " << dh << '\n';
1936 	  y += dh;
1937 	  of << replace(os.str(),'\n','�');
1938 	  of << "\n,\n]\n";
1939 	}
1940       }
1941     }
1942     return y;
1943   }
1944 
insert_before(int before_position,bool newurl,int mws)1945   bool History_Pack::insert_before(int before_position,bool newurl,int mws){
1946     if (!_insert)
1947       return false;
1948     // get filename
1949     const char * newfile ;
1950     switch (mws){
1951     case 1:
1952       newfile = load_file_chooser("Load maple worksheet","*.mws","*.mws",0,false);
1953       break;
1954     case 3:
1955       newfile = load_file_chooser("Load ti89 program","*.89*","*.89*",0,false);
1956       break;
1957     case 7:
1958       newfile = load_file_chooser("Load V200 program","*.v2*","*.v2*",0,false);
1959       break;
1960     default:
1961       newfile = load_file_chooser("Load worksheet", "*.xws", "session.xws",0,false);
1962     }
1963     // check filename
1964     if ( !newfile )
1965       return false;
1966     if (!is_file_available(newfile)){
1967       fl_message("%s",("File "+string(newfile)+" does not exist.").c_str());
1968       return false;
1969     }
1970     if (mws==3 || mws==7){
1971       if (xcas_mode(contextptr)!=3){
1972 	int i=fl_ask("%s",gettext("Set compatibility mode to TI?"));
1973 	if (i)
1974 	  xcas_mode(contextptr)=3;
1975       }
1976       gen tmp=_unarchive_ti(string2gen(newfile,false),contextptr);
1977       if (is_undef(tmp))
1978 	return false;
1979       // create
1980       newfile=(remove_extension(newfile)+".xws").c_str();
1981       if (newurl)
1982 	new_url(newfile);
1983       string xcasti=remove_extension(newfile)+".ti";
1984       ofstream out(xcasti.c_str());
1985       out << tmp << '\n';
1986       out.close();
1987       History_Fold * o = get_history_fold(this);
1988       if (o){
1989 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
1990 	int pos=o->pack->_sel_begin;
1991 	Fl_Widget * e=new_program(max(o->pack->w()-o->pack->_printlevel_w,1),o->h()/2,o->pack);
1992 	change_group_fontsize(e,o->labelsize());
1993 	o->pack->add_entry(pos,e);
1994 	if (Editeur * ed=dynamic_cast<Editeur *>(e)){
1995 	  ed->editor->buffer()->insertfile(xcasti.c_str(),ed->editor->insert_position());
1996 	  ed->editor->label(xcasti.c_str());
1997 	  ed->output->value(remove_path(xcasti).c_str());
1998 	  ed->output->redraw();
1999 	  Fl::focus(ed->editor);
2000 	}
2001       }
2002       return true;
2003     }
2004     if (mws==1){
2005       // Translate to xcas worksheet
2006       string xcasws=remove_extension(newfile)+".xws";
2007       if (is_file_available(xcasws.c_str())){
2008 	int i=fl_ask("%s",(gettext("File ")+xcasws+gettext(" exists. Overwrite?")).c_str());
2009 	if (!i)
2010 	  return false;
2011       }
2012       if (xcas_mode(contextptr)!=mws){
2013 	fl_message("%s",gettext("Translating worksheet and setting compatibility mode to maple"));
2014 	xcas_mode(contextptr)=mws;
2015       }
2016       ifstream in(newfile);
2017       ofstream out(xcasws.c_str());
2018       mws2xws(in,out,49,87,626,labelsize()+1);
2019       in.close();
2020       out.close();
2021       newfile = xcasws.c_str();
2022     }
2023     if (newurl)
2024       new_url(newfile);
2025     return insert_url(newfile,before_position);
2026   }
2027 
insert_url(const char * urlname0,int before_position)2028   bool History_Pack::insert_url(const char * urlname0,int before_position){
2029     if (!urlname0 || !_insert )
2030       return false;
2031     string urlname = unix_path(urlname0).c_str();
2032 #if 1 // ndef WIN32
2033     string sn=get_path(urlname);
2034     if (!sn.empty()){
2035 #ifndef HAVE_NO_CWD
2036       //_cd(string2gen(sn,false),contextptr);
2037       chdir(sn.c_str());
2038 #endif
2039     }
2040 #endif
2041     FILE * f=fopen(urlname.c_str(),"r");
2042     if (!f){
2043       fl_message("%s",("Unable to load "+urlname).c_str());
2044       return false;
2045     }
2046     string s;
2047     char c;
2048     bool casio=false;
2049     int POS;
2050     for (POS=0;;++POS){
2051       c=fgetc(f);
2052       if (POS==0 && c==0){
2053 	casio=true;
2054       }
2055       if (feof(f))
2056 	break;
2057       s += c;
2058     }
2059     fclose(f);
2060     unsigned ss=s.size();
2061     bool exec=false;
2062     int fontsize=labelsize();
2063     int newpos=-1;
2064     Fl_Font police=FL_HELVETICA;
2065     if (ss>7 && s.substr(0,8)=="// xcas "){
2066       unsigned pos=s.find('\n');
2067       if (pos>=0 && pos<ss){
2068 	string options=s.substr(8,pos-8);
2069 	// remaining session
2070 	s=s.substr(pos+1,ss-pos-1);
2071 	// parse options
2072 	pos=0;
2073 	unsigned optsize=options.size();
2074 	string optname,optvalue;
2075 	bool afterequal=false;
2076 	for (;pos<optsize;++pos){
2077 	  if (options[pos]=='='){
2078 	    optvalue="";
2079 	    afterequal=true;
2080 	    continue;
2081 	  }
2082 	  if (options[pos]==' ' || pos==optsize-1){
2083 	    if (pos==optsize-1)
2084 	      optvalue += options[pos];
2085 	    if (afterequal && !optname.empty() && !optvalue.empty()){
2086 	      if (optname=="exec")
2087 		exec = (optvalue=="true");
2088 	      if (optname=="fontsize")
2089 		fontsize = atoi(optvalue.c_str());
2090 	      if (optname=="font")
2091 		police = Fl_Font(atoi(optvalue.c_str()));
2092 	      if (optname=="xcas_mode")
2093 		xcas_mode(contextptr)=atoi(optvalue.c_str());
2094 	      if (optname=="currentlevel"){
2095 		newpos=atoi(optvalue.c_str());
2096 		if (before_position>0)
2097 		  newpos += before_position;
2098 	      }
2099 	      if (optname=="pixon"){
2100 		newpos=atoi(optvalue.c_str());
2101 		if (newpos>=1 && newpos<=9)
2102 		  pixon_size=newpos;
2103 	      }
2104 	    }
2105 	    optname="";
2106 	    afterequal=false;
2107 	  }
2108 	  else {
2109 	    if (afterequal)
2110 	      optvalue += options[pos];
2111 	    else
2112 	      optname +=  options[pos];
2113 	  }
2114 	}
2115       }
2116     }
2117     if (ss>8  && s.substr(0,8)=="{VERSION"){
2118       // Maple translate
2119 #ifdef HAVE_SSTREAM
2120       istringstream in(s);
2121       ostringstream out;
2122 #else
2123       istrstream in(s.c_str());
2124       ostrstream out;
2125 #endif
2126       mws2xws(in,out,49,87,626,labelsize()+1);
2127       s=out.str();
2128       if (xcas_mode(contextptr)!=1){
2129 	fl_message("%s",gettext("Translating maple worksheet and setting compatibility mode to maple"));
2130 	xcas_mode(contextptr)=1;
2131       }
2132       new_url((remove_extension(urlname)+".xws").c_str());
2133     }
2134     if (casio && ss>4){
2135       s=casio2xws(s.c_str(),POS,fontsize,contextptr);
2136       new_url((remove_extension(urlname)+".xws").c_str());
2137     }
2138     bool res= _insert(this,s.c_str(),s.size(),before_position);
2139     if (exec){
2140       Fl_Group * g = dynamic_cast<Fl_Group *>(child(0));
2141       if (g && !dynamic_cast<Figure *>(g) && g->children()){
2142 	eval_below=true;
2143 	History_Pack_cb_eval(g->child(0),0);
2144       }
2145     }
2146     focus(newpos,true);
2147     labelfont(police);
2148     change_group_fontsize(this,max(8,fontsize));
2149     return res;
2150   }
2151 
editor_hsize(Fl_Widget * w)2152   int editor_hsize(Fl_Widget * w){
2153     if (!w)
2154       return 0;
2155     return w->labelsize()+12;
2156     Fl_Group * wd = w->parent();
2157     while (wd && wd->parent())
2158       wd=wd->parent();
2159     if (wd && w->w()<wd->w()*0.7)
2160       return w->labelsize()+24;
2161     else
2162       return w->labelsize()+12;
2163   }
2164 
add_entry(int n)2165   bool History_Pack::add_entry(int n){
2166     if (!new_question)
2167       return false;
2168     Fl_Widget * q=new_question(max(w()-_printlevel_w,1),editor_hsize(this));
2169     add_entry(n,q);
2170     return true;
2171   }
2172 
2173 
add_entry(int n,Fl_Widget * q)2174   void History_Pack::add_entry(int n,Fl_Widget * q){
2175     q->labelsize(labelsize());
2176     q->labelfont(labelfont());
2177     if (Fl_Input_ * i=dynamic_cast<Fl_Input_ *>(q)){
2178       i->textsize(labelsize());
2179       i->textfont(labelfont());
2180     }
2181     if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(q)){
2182       ed->Fl_Text_Display::textsize(labelsize());
2183       vector<Fl_Text_Display::Style_Table_Entry> & v=ed->styletable;
2184       for (unsigned i=0;i<v.size();++i)
2185 	v[i].size=labelsize();
2186     }
2187     if (q->w()>w()-_printlevel_w)
2188       q->resize(q->x(),q->y(),w()-_printlevel_w,q->h());
2189     int addh=1;
2190     Fl_Group::current(0);
2191     Fl_Tile * g = new Fl_Tile(q->x(),q->y(),q->w(),q->h()+addh);
2192     g->labelfont(q->labelfont());
2193     g->end();
2194     g->add(q);
2195     Log_Output * lg = new Log_Output(q->x(),q->y()+q->h(),q->w(),addh);
2196     lg->labelsize(labelsize());
2197     lg->labelfont(labelfont());
2198     lg->textsize(labelsize());
2199     lg->textfont(labelfont());
2200     lg->textcolor(Xcas_log_color);
2201     lg->color(Xcas_log_background_color);
2202     g->add(lg);
2203     g->resizable(q);
2204     add_entry(n,g);
2205     focus(n,true);
2206   }
2207 
add_entry(int n,Fl_Group * g)2208   void History_Pack::add_entry(int n,Fl_Group * g){
2209     add_history_map(g,undo_position);
2210     int hh=h()+_spacing+g->h();
2211     if (_resize_above)
2212       increase_size(this,_spacing+g->h());
2213     int m=children();
2214     int ynew=y();
2215     if (n==-1 || n>=m)
2216       ynew += h();
2217     else
2218       ynew = child(n)->y();
2219     Fl_Widget::resize(x(),y(),w(),hh);
2220     g->resize(x(),ynew,min(w(),g->w()),g->h());
2221     if (n==-1 || n>=m)
2222       add(g);
2223     else
2224       insert(*g,n);
2225     modified(true);
2226     resize();
2227     Fl_Widget * p= parent();
2228     if (dynamic_cast<HScroll *>(p)) // this will resize children horizontally
2229       p->resize(p->x(),p->y(),p->w(),p->h());
2230     parent_redraw(this);
2231     redraw();
2232   }
2233 
new_question_multiline_input(int W,int H)2234   Fl_Widget * new_question_multiline_input(int W,int H){
2235     Fl_Group::current(0);
2236     Multiline_Input_tab * w=new Multiline_Input_tab(0,0,W,H);
2237     w->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
2238     w->callback(History_Pack_cb_eval,0);
2239     w->textcolor(Xcas_input_color);
2240     w->color(Xcas_input_background_color);
2241     return w;
2242   }
2243 
new_question_editor(int W,int H)2244   Fl_Widget * new_question_editor(int W,int H){
2245     Fl_Group::current(0);
2246     Fl_Text_Buffer * b = new Fl_Text_Buffer;
2247     Xcas_Text_Editor * w=new Xcas_Text_Editor(0,0,W,H,b);
2248     w->scrollbar_width(12);
2249     w->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
2250     w->callback(History_Pack_cb_eval,0);
2251     w->textcolor(Xcas_input_color);
2252     w->color(Xcas_input_background_color);
2253     w->buffer()->add_modify_callback(style_update, w);
2254     return w;
2255   }
2256 
new_question_equation(int W,int H)2257   Fl_Widget * new_question_equation(int W,int H){
2258     Fl_Group::current(0);
2259     Equation * w=new Equation(0,0,W,H,"",0);
2260     w->output_equation=false;
2261     w->select();
2262     w->cb_enter=History_Pack_cb_eval;
2263     w->attr.text_color=Xcas_equation_input_color;
2264     w->color(Xcas_equation_input_background_color);
2265     return w;
2266   }
2267 
Comment_cb_eval(Fl_Multiline_Input * q,void *)2268   void Comment_cb_eval(Fl_Multiline_Input * q , void*){
2269     if(!Fl::event_shift()){
2270       // focus on next input
2271       History_Pack * hp=get_history_pack(q);
2272       if (hp){
2273 	hp->_sel_begin=-1;
2274 	hp->set_sel_begin(xcas::Xcas_input_focus);
2275 	if (hp->_sel_begin<hp->children()-1){
2276 	  Fl_Widget * w=hp->child(hp->_sel_begin+1);
2277 	  if (Fl_Group * g=dynamic_cast<Fl_Group *>(w)){
2278 	    if (g->children()){
2279 	      w=g->child(0);
2280 	      if ( (g=dynamic_cast<Fl_Group *>(w)) ){
2281 		if (g->children())
2282 		  w=g->child(0);
2283 	      }
2284 	      Fl::focus(w);
2285 	      if (Fl_Input_ * i=dynamic_cast<Fl_Input_ *>(w)){
2286 		int is=strlen(i->value());
2287 		i->position(is,is);
2288 	      }
2289 	    }
2290 	  }
2291 	}
2292       }
2293     }
2294   }
2295 
new_comment_input(int W,int H)2296   Fl_Widget * new_comment_input(int W,int H){
2297     Fl_Group::current(0);
2298     Comment_Multiline_Input * w=new Comment_Multiline_Input(0,0,W,H,"");
2299     w->textcolor(Xcas_comment_color);
2300     w->color(Xcas_comment_background_color);
2301     w->callback((Fl_Callback *) Comment_cb_eval);
2302     w->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
2303     return w;
2304   }
2305 
new_tableur(int W,int H,const History_Pack * pack)2306   Fl_Widget * new_tableur(int W,int H,const History_Pack * pack){
2307     Fl_Group::current(0);
2308     Tableur_Group * t = new Tableur_Group(0,0,W,H,pack->labelsize(),0);
2309     t->labelfont(pack->labelfont());
2310     t->table->labelfont(pack->labelfont());
2311     if (t && t->table)
2312       Fl::focus(t->table);
2313     set_colors(t);
2314     return t;
2315   }
2316 
new_program(int W,int H,const History_Pack * pack)2317   Fl_Widget * new_program(int W,int H,const History_Pack * pack){
2318     Fl_Group::current((Fl_Group *)pack);
2319     Editeur * t = new Editeur(0,0,W,H);
2320     t->labelfont(pack->labelfont());
2321     t->callback(History_Pack_cb_eval,0);
2322     set_colors(t);
2323     return t;
2324   }
2325 
new_figure(int W,int H,const History_Pack * pack,bool dim3,bool approx)2326   Fl_Group * new_figure(int W,int H,const History_Pack * pack,bool dim3,bool approx){
2327 #if defined GRAPH_WINDOW && defined __APPLE__
2328     if (dim3) fl_alert("Sorry, 3d geometry does not work on Mac OS.");
2329     dim3=false; // 3d geo does not work on mac
2330 #endif
2331     Fl_Group::current(0);
2332     Figure * t = new Figure(0,0,W,H,pack->labelsize(),dim3);
2333     t->labelfont(pack->labelfont());
2334     t->geo->hp->labelfont(pack->labelfont());
2335     t->geo->approx=approx;
2336     t->geo->hp->contextptr=pack->contextptr;
2337     if (dim3)
2338       t->lt->line_type(_POINT_WIDTH_5);
2339     set_colors(t);
2340     return t;
2341   }
2342 
new_logo(int W,int H,const History_Pack * pack)2343   Fl_Group * new_logo(int W,int H,const History_Pack * pack){
2344     Fl_Group::current(0);
2345     Logo * t = new Logo(0,0,W,H,pack->labelsize());
2346     t->hp->contextptr=pack->contextptr;
2347     t->t->turtleptr=&giac::turtle_stack(pack->contextptr);
2348     turtle(pack->contextptr).widget = t->t;
2349     set_colors(t);
2350     return t;
2351   }
2352 
find_log_output(Fl_Group * g)2353   Log_Output * find_log_output(Fl_Group * g){
2354     if (!g)
2355       return 0;
2356     Log_Output * otmp=0;
2357     int m=g->children();
2358     for (int i=0;i<m;++i){
2359       if ( (otmp=dynamic_cast<Log_Output *>(g->child(i))) )
2360 	break;
2361     }
2362     return otmp;
2363   }
2364 
eval()2365   void History_Fold::eval(){
2366     if (pack->children()){
2367       pack->eval_below=true;
2368       const History_Pack * hp=get_history_pack(this);
2369       if (hp)
2370 	pack->eval_next=hp->eval_below;
2371       Fl_Group * g = dynamic_cast<Fl_Group *>(pack->child(0));
2372       if (History_Fold * hf=dynamic_cast<History_Fold *>(g))
2373 	hf->eval();
2374       else
2375 	if (g && !dynamic_cast<Figure *>(g) && g->children())
2376 	  History_Pack_cb_eval(g->child(0),0);
2377     }
2378   }
2379 
2380   const int logptrinitlines=4;
2381 
History_Pack_Group_eval(Fl_Group * g,bool add_group)2382   void History_Pack_Group_eval(Fl_Group * g,bool add_group){
2383     if (History_Fold * hf=dynamic_cast<History_Fold *>(g)){
2384       hf->eval();
2385       return;
2386     }
2387     int m=g->children();
2388     if (!m)
2389       return;
2390     Fl_Widget * q = g->child(0);
2391     History_Pack * p = dynamic_cast<History_Pack * >(g->parent());
2392     if (!p) return;
2393     // add an entry if none are below or focus on next entry
2394     int N=p->find(g),M=p->children();
2395     if (N && p->next_delay)
2396       usleep(p->next_delay);
2397     // Search in g->children if there is a Log_Output available
2398     if (Xcas_DispG)
2399       xcas_dispg_entries=Xcas_DispG->plot_instructions.size();
2400     Log_Output * otmp=find_log_output(g);
2401     int deltalog=0;
2402     if (!otmp){
2403       Fl_Group::current(0);
2404       otmp = new Log_Output(q->x(),q->y()+q->h(),q->w(),logptrinitlines*q->labelsize()+14);
2405       deltalog=otmp->h();
2406       g->Fl_Widget::resize(g->x(),g->y(),g->w(),g->h()+deltalog);
2407       otmp->labelsize(q->labelsize());
2408       otmp->labelfont(q->labelfont());
2409       otmp->textsize(q->labelsize());
2410       otmp->textfont(q->labelfont());
2411       otmp->textcolor(Xcas_log_color);
2412       g->insert(*otmp,1);
2413       ++m;
2414     }
2415     else {
2416       deltalog=otmp->h();
2417       otmp->value("");
2418       // resize otmp
2419       otmp->resize(otmp->x(),otmp->y(),otmp->w(),logptrinitlines*otmp->labelsize()+14);
2420       deltalog = otmp->h()-deltalog;
2421       g->Fl_Widget::resize(g->x(),g->y(),g->w(),g->h()+deltalog);
2422       g->insert(*otmp,1);
2423     }
2424     for (int i=g->find(otmp)+1;i<g->children();i++){
2425       Fl_Widget * wtmp=g->child(i);
2426       wtmp->resize(wtmp->x(),wtmp->y()+deltalog,wtmp->w(),wtmp->h());
2427     }
2428     if (logstream)
2429       delete logstream;
2430     logstream = new owstream(otmp,p->contextptr) ;
2431     logptr(logstream,p->contextptr);
2432     // p->modified(false);
2433     g->resizable(NULL);
2434     Fl_Widget * a, * b=q;
2435     if (Fl_Scroll * s = dynamic_cast<Fl_Scroll *>(q))
2436       b = s->child(0);
2437     a=p->eval(b);
2438     if (a==0 && g->children()==3){
2439       Fl_Widget * tmp =g->child(2);
2440       int tmph=tmp->h();
2441       g->remove(tmp);
2442       delete tmp;
2443       g->Fl_Widget::resize(g->x(),g->y(),g->w(),g->h()-tmph);
2444       g->resizable(g);
2445     }
2446     if (a==0 || a==b) { // a==0 or a==b: no output
2447       output_resize_parent(otmp);
2448       // add_group=false;
2449       p->doing_eval=false;
2450       if (!a && p->eval_below) // if a==b, widget is an eval-terminal widget
2451 	p->next(N);
2452       return;
2453     }
2454     // bool computing=false;
2455     if (Fl_Output * out =dynamic_cast<Fl_Output *>(a)){
2456       if (strcmp(out->value(),gettext("Unable to launch thread. Press STOP to interrupt."))==0)
2457 	output_resize_parent(otmp);
2458     }
2459     p->resize();
2460     int ah=0;
2461     if (m>2){
2462       ah = g->child(2)->h();
2463       Fl_Widget * wid=g->child(2);
2464       g->remove(wid);
2465       if (!dynamic_cast<Gen_Value_Slider *>(wid)){
2466 	delete wid; // must not delete a slider because we are in it's callback
2467       }
2468     }
2469     a->resize(q->x(),otmp->y()+otmp->h(),g->w(),a->h());
2470     g->Fl_Widget::resize(g->x(),g->y(),g->w(),g->h()+a->h()-ah);
2471     g->insert(*a,2);
2472     g->resizable(g);
2473     bool fin_pack=N>=M-1;
2474     if (!fin_pack){ // if next level is not a multiline_input do like at end
2475       Fl_Widget * tmp = p->child(N+1);
2476       if (Fl_Tile * tmps = dynamic_cast<Fl_Tile *>(tmp)){
2477 	if (tmps->children())
2478 	  tmp=tmps->child(0);
2479       }
2480       if (!dynamic_cast<Fl_Input *>(tmp) && !dynamic_cast<Xcas_Text_Editor*>(tmp))
2481 	fin_pack =true;
2482     }
2483     if (fin_pack){
2484       p->next_delay=0;
2485       if (add_group){
2486 	p->add_entry(N+1);
2487 	if (p->children()>N+1)
2488 	  p->child(N+1)->resize(p->child(N)->x(),p->child(N)->y()+p->child(N)->h()+p->_spacing,p->child(N+1)->w(),p->child(N+1)->h());
2489       }
2490     }
2491     else {
2492       Fl_Widget * tmp = p->child(N+1);
2493       Fl_Group * tmpg = dynamic_cast<Fl_Group *>(tmp);
2494       if (tmpg && tmpg->children()){
2495 	Fl::focus(tmpg->child(0));
2496 	if (Fl_Input * i = dynamic_cast<Fl_Input *>(tmpg->child(0))){
2497 	  /* int is=strlen(i->value()); */
2498 	  i->position(0,0); // was i->position(is,is);
2499 	}
2500       }
2501     }
2502     Fl_Scroll * s = dynamic_cast<Fl_Scroll * > (p->parent());
2503     if (s){
2504       N=min(N,p->children()-1);
2505       if (p->child(N)->y()+p->child(N)->h()-p->y()>s->yposition()+s->h()-2*p->labelsize()){
2506 	// int s1=s->yposition()+p->child(N)->h();
2507 	int s1=p->child(N)->y()-p->y(); // begin of evaluated widget
2508 	if (p->child(N)->h()>s->h()-2*p->labelsize()){ // evaluated widget too large
2509 	  s1=p->child(N+1)->y()+2*p->labelsize()-p->y()-s->h();
2510 	}
2511 	s1=min(p->h()-s->h(),s1);
2512 #ifdef _HAVE_FL_UTF8_HDR_
2513 	s->scroll_to(0,max(0,s1));
2514 #else
2515 	s->position(0,max(0,s1));
2516 #endif
2517 	if (!p->doing_eval && s->parent())
2518 	  s->parent()->redraw();
2519       }
2520     }
2521     p->_sel_begin=N+1;
2522     p->_sel_end=-1;
2523     p->redraw();
2524   }
2525 
parent_skip_scroll(const Fl_Widget * g)2526   Fl_Group * parent_skip_scroll(const Fl_Widget * g){
2527     if (!g)
2528       return 0;
2529     Fl_Group * res = g->parent();
2530     if (res){
2531       if (Fl_Scroll * s = dynamic_cast<Fl_Scroll *>(res))
2532 	res=s->parent();
2533     }
2534     return res;
2535   }
2536 
History_Pack_cb_eval(Fl_Widget * q,void *)2537   void History_Pack_cb_eval(Fl_Widget * q , void*){
2538     Fl_Group * g = q->parent();
2539     if (g){ // Check if the widget is embedded in a Fl_Scroll
2540       if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(g)){
2541 	g=s->parent();
2542 	q=s;
2543       }
2544     }
2545     History_Pack * hp = dynamic_cast<History_Pack *>(g->parent());
2546     if (!hp || hp->doing_eval)
2547       return;
2548     if (hp->eval_below){
2549       hp->doing_eval=true;
2550       io_graph(false,hp->contextptr);
2551     }
2552     History_Pack_Group_eval(g,true);
2553     hp->doing_eval=false;
2554     io_graph(true,hp->contextptr);
2555     /*
2556 #ifdef HAVE_LIBPTHREAD
2557     // If this a concurrent call to a thread_eval in the same context
2558     // we do nothing
2559     if (is_context_busy(hp->contextptr)){
2560       *logptr(hp->contextptr) << "Thread is busy. Try again later." << '\n';
2561       return;
2562     }
2563 #endif
2564     if (hp && hp->eval_below) {
2565       hp->doing_eval=true;
2566       io_graph(false,hp->contextptr);
2567       int n=hp->children();
2568       int i=hp->find(g);
2569       int pos=i;
2570       for (;i<n;++i){
2571 	Fl_Group * tmp = dynamic_cast<Fl_Group *>(hp->child(i));
2572 	History_Pack_Group_eval(tmp,i==n-1);
2573       }
2574       // Check for a Geometry child in parent, update it
2575       Fl_Group * hpp = parent_skip_scroll(hp);
2576       if (hpp){
2577 	int N=hpp->children();
2578 	for (int i=0;i<N;++i){
2579 	  Graph2d3d * geo = dynamic_cast<Graph2d3d *>(hpp->child(i));
2580 	  if (geo)
2581 	    geo->update(hp,pos);
2582 	}
2583       }
2584       io_graph(true,hp->contextptr);
2585       hp->doing_eval=false;
2586     }
2587     else {
2588       if (g && !g->find(q) )
2589 	History_Pack_Group_eval(g,true);
2590     }
2591     */
2592   }
2593 
History_cb_Save(Fl_Widget * m,void *)2594   void History_cb_Save(Fl_Widget* m , void*) {
2595     if (m && m->parent()){
2596       History_Fold * o = get_history_fold(m);
2597       if (o)
2598 	o->pack->save();
2599     }
2600   }
2601 
close()2602   bool History_Fold::close(){
2603     if (pack){
2604       if (!pack->close("Buffer"))
2605 	return false;
2606     }
2607     autosave_rm();
2608     Fl_Group * g = parent();
2609     Fl::focus(g);
2610     clear();
2611     if (g){
2612       g->remove(this);
2613       parent_redraw(g);
2614       g = g->parent();
2615       if (HScroll * hs=dynamic_cast<HScroll *>(g))
2616 	hs->resize();
2617     }
2618     return true;
2619   }
2620 
History_cb_Kill(Fl_Widget * m,void *)2621   void History_cb_Kill(Fl_Widget * m , void*) {
2622     if (m && m->parent()){
2623       History_Fold * o = get_history_fold(m);
2624       if (o) o->close();
2625     }
2626   }
2627 
hf_Kill(Fl_Button * m,void *)2628   void hf_Kill(Fl_Button * m , void*) {
2629     if (m && m->parent()){
2630       History_Fold * o = get_history_fold(m);
2631       if (o && o->parent()){
2632 	Fl::focus(o->parent());
2633 	o->close();
2634       }
2635     }
2636   }
2637 
History_cb_Save_as(Fl_Widget * m,void *)2638   void History_cb_Save_as(Fl_Widget* m , void*) {
2639     if (m && m->parent()){
2640       History_Fold * o = get_history_fold(m);
2641       if (o)
2642 	o->pack->save_as(0);
2643     }
2644   }
2645 
mode2extension(int mode)2646   string mode2extension(int mode){
2647     switch (mode){
2648     case -1:
2649       return "xw";
2650     case 1:
2651       return "map";
2652     case 2:
2653       return "mu";
2654     case 3:
2655       return "ti";
2656     case 256:
2657       return "py";
2658     default:
2659       return "cas";
2660     }
2661   }
2662 
khicas_state(GIAC_CONTEXT)2663   string khicas_state(GIAC_CONTEXT){
2664     giac::gen g(giac::_VARS(-1,contextptr));
2665     int b=python_compat(contextptr);
2666     python_compat(0,contextptr);
2667     string s(g.print(contextptr));
2668     python_compat(b,contextptr);
2669     // if (b==0)  b=1; // impose Python mode
2670     s += "; python_compat(";
2671     s +=  giac::print_INT_(b);
2672     s += ");angle_radian(";
2673     s += angle_radian(contextptr)?'1':'0';
2674     s += ");";
2675     return s;
2676   }
2677 
endian_exchange(unsigned & l)2678   void endian_exchange(unsigned & l){
2679     unsigned char * ptr=(unsigned char *)&l;
2680     unsigned char c=ptr[0];
2681     ptr[0]=ptr[3];
2682     ptr[3]=c;
2683     c=ptr[1];
2684     ptr[1]=ptr[2];
2685     ptr[2]=c;
2686   }
2687 
endian_exchange(unsigned short & l)2688   void endian_exchange(unsigned short & l){
2689     unsigned char * ptr=(unsigned char *)&l;
2690     unsigned char c=ptr[0];
2691     ptr[0]=ptr[1];
2692     ptr[1]=c;
2693   }
2694 
save_as_text(ostream & of,int mode,History_Pack * pack)2695   void save_as_text(ostream & of,int mode,History_Pack * pack){
2696     const giac::context * contextptr=pack?pack->contextptr:context0;
2697     bool casio=mode==-1;
2698     bool python=mode>=256;
2699     if (casio){
2700       mode=0;
2701       //python=true;
2702     }
2703     mode = mode & 0xff;
2704     int save_maple_mode=xcas_mode(contextptr);
2705     int save_python=python_compat(contextptr);
2706     python_compat(python,contextptr);
2707     int n=pack->children();
2708     vector<string> casiosave;
2709     string casioedit;
2710     for (int i=0;i<n;i++){
2711       if (!of)
2712 	break;
2713       Fl_Widget * wid=pack->child(i);
2714       if (History_Fold * hf=dynamic_cast<History_Fold *>(wid)){
2715 	if (!casio)
2716 	  save_as_text(of,mode,hf->pack);
2717 	continue;
2718       }
2719       Fl_Group * g;
2720       Fl_Widget *wid2=0;
2721       while ( (g=dynamic_cast<Fl_Group *>(wid)) ){
2722 	if (g->children()>2)
2723 	  wid2=g->child(g->children()-1);
2724 	if (Figure * fig=dynamic_cast<Figure *>(g))
2725 	  break;
2726 	if (Editeur * ed=dynamic_cast<Editeur *>(wid))
2727 	  break;
2728 	if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(wid))
2729 	  break;
2730 	if (g->children())
2731 	  wid=g->child(0);
2732 	else
2733 	  break;
2734       }
2735       if (Editeur * ed=dynamic_cast<Editeur *>(wid)){
2736 	if (casio)
2737 	  casioedit+=unlocalize(ed->value())+'\n';
2738 	else {
2739 	  xcas_mode(contextptr)=mode;
2740 	  gen g(ed->value(),contextptr);
2741 	  if (g.is_symb_of_sommet(at_nodisp))
2742 	    g=g._SYMBptr->feuille;
2743 	  if (g.is_symb_of_sommet(at_sto) && python_compat(contextptr))
2744 	    g=g._SYMBptr->feuille[0];
2745 	  string s(unlocalize(g.print(contextptr)));
2746 	  of << s << '\n';
2747 	  xcas_mode(contextptr)=save_maple_mode;
2748 	}
2749       }
2750       if (Xcas_Text_Editor * xed=dynamic_cast<Xcas_Text_Editor *>(wid)){
2751 	xcas_mode(contextptr)=mode;
2752 	string s(unlocalize(xed->value()));
2753 	if (casio){
2754 	  casiosave.push_back(s);
2755 	  if (Equation * eq=dynamic_cast<Equation *>(wid2))
2756 	    casiosave.push_back(eq->get_data().print(contextptr));
2757 	  else {
2758 	    if (Fl_Group * gr=dynamic_cast<Fl_Group *>(wid2)){
2759 	      if (gr->children()){
2760 		if (Graph2d * g=dynamic_cast<Graph2d *>(gr->child(0)))
2761 		  casiosave.push_back("Graphic object");
2762 	      }
2763 	    }
2764 	    else casiosave.push_back("");
2765 	  }
2766 	}
2767 	else
2768 	  of << s << '\n';
2769 	xcas_mode(contextptr)=save_maple_mode;
2770       }
2771       if (Figure * fig=dynamic_cast<Figure *>(g)){
2772 	if (!casio)
2773 	  save_as_text(of,mode,fig->geo->hp);
2774 	continue;
2775       }
2776       if (Comment_Multiline_Input * co=dynamic_cast<Comment_Multiline_Input *>(wid)){
2777 	if (casio){
2778 	  casiosave.push_back("/*"+string(co->value())+"*/");
2779 	  casiosave.push_back("");
2780 	}
2781 	else
2782 	  of << (mode==1?"++ ":"/* ") << co->value() << (mode==1?" ++":" */") << '\n';
2783       }
2784       if (Multiline_Input_tab * mi=dynamic_cast<Multiline_Input_tab *>(wid)){
2785 	if (!casio && strlen(mi->value())){
2786 	  gen tmp=mi->g();
2787 	  xcas_mode(contextptr)=mode;
2788 	  of << tmp.print(contextptr) << " ;" << '\n';
2789 	  xcas_mode(contextptr)=save_maple_mode;
2790 	}
2791       }
2792       if (Equation * eq=dynamic_cast<Equation *>(wid)){
2793 	xcas_mode(contextptr)=mode;
2794 	string s(eq->get_data().print(contextptr));
2795 	if (casio){
2796 	  casiosave.push_back(s);
2797 	  casiosave.push_back("");
2798 	}
2799 	else
2800 	  of << s << " ;" << '\n';
2801 	xcas_mode(contextptr)=save_maple_mode;
2802       }
2803     }
2804     python_compat(save_python,contextptr);
2805     if (!casio) return;
2806     // output in casio mode
2807     string s(khicas_state(contextptr));
2808     unsigned l=s.size();
2809     endian_exchange(l);
2810     of.write((char *)&l,4);
2811     of.write((const char *)s.c_str(),s.size());
2812     l=casioedit.size();
2813     endian_exchange(l);
2814     of.write((char *)&l,4);
2815     of.write((const char *)casioedit.c_str(),casioedit.size());
2816     for (int i=0;i<casiosave.size();++i){
2817       // assume 1 in/1 out
2818       string & s=casiosave[i];
2819       unsigned short l=s.size();
2820       if (l==0) continue;
2821       endian_exchange(l);
2822       of.write((char *)&l,2);
2823       l=0;
2824       of.write((char *)&l,2);
2825       char c=i%2?1:0;
2826       of.write(&c,1);
2827       c=1;
2828       of.write(&c,1);
2829       of.write(s.c_str(),s.size());
2830     }
2831     l=0;
2832     of.write((char *)&l,4);
2833   }
2834 
History_cb_save_as_text(Fl_Widget * m,int mode)2835   void History_cb_save_as_text(Fl_Widget * m,int mode){
2836     if (m && m->parent()){
2837       History_Fold * o = get_history_fold(m);
2838       if (o){
2839 	string tmp=o->pack->url?remove_extension(*o->pack->url):"session";
2840 	tmp += "."+mode2extension(mode);
2841 	char * newfile = file_chooser(gettext("Export worksheet as"), ("*."+mode2extension(mode)).c_str(), tmp.c_str());
2842 	// check filename
2843 	if ( !newfile )
2844 	  return ;
2845 	ofstream of(newfile);
2846 	save_as_text(of,mode,o->pack);
2847       }
2848     }
2849   }
2850 
History_cb_Save_as_xcas_casio(Fl_Widget * m,void *)2851   void History_cb_Save_as_xcas_casio(Fl_Widget* m , void*) {
2852     History_cb_save_as_text(m,-1);
2853   }
2854 
History_cb_Save_as_xcas_text(Fl_Widget * m,void *)2855   void History_cb_Save_as_xcas_text(Fl_Widget* m , void*) {
2856     History_cb_save_as_text(m,0);
2857   }
2858 
History_cb_Save_as_xcaspy_text(Fl_Widget * m,void *)2859   void History_cb_Save_as_xcaspy_text(Fl_Widget* m , void*) {
2860     History_cb_save_as_text(m,256);
2861   }
2862 
History_cb_Save_as_maple_text(Fl_Widget * m,void *)2863   void History_cb_Save_as_maple_text(Fl_Widget* m , void*) {
2864     History_cb_save_as_text(m,1);
2865   }
2866 
History_cb_Save_as_mupad_text(Fl_Widget * m,void *)2867   void History_cb_Save_as_mupad_text(Fl_Widget* m , void*) {
2868     History_cb_save_as_text(m,2);
2869   }
2870 
History_cb_Save_as_ti_text(Fl_Widget * m,void *)2871   void History_cb_Save_as_ti_text(Fl_Widget* m , void*) {
2872     History_cb_save_as_text(m,3);
2873   }
2874 
History_cb_Insert(Fl_Widget * m,void *)2875   void History_cb_Insert(Fl_Widget* m , void*) {
2876     if (m && m->parent()){
2877       History_Fold * o = get_history_fold(m);
2878       if (o){
2879 	o->pack->insert_before(o->pack->_sel_begin);
2880       }
2881     }
2882   }
2883 
History_cb_Load(Fl_Widget * m,void *)2884   void History_cb_Load(Fl_Widget* m , void*) {
2885     if (m && m->parent()){
2886       History_Fold * o = get_history_fold(m);
2887       if (o){
2888 	if (o->pack->_modified){
2889 	  int i=confirm_close(gettext("Current buffer modified. Save?"));
2890 	  if (i==0)
2891 	    return;
2892 	  if (i!=2)
2893 	    if (!o->pack->save())
2894 	      return;
2895 	}
2896 	// Clear current pack
2897 	o->pack->clear();
2898 	if (o->pack->insert_before(-1,true))
2899 	  o->pack->clear_modified();
2900 	else
2901 	  o->close();
2902       }
2903     }
2904   }
2905 
History_cb_Fold(Fl_Widget * m,void *)2906   void History_cb_Fold(Fl_Widget* m , void*) {
2907     if (m ){
2908       History_Fold * o = get_history_fold_focus(m);
2909       if (o)
2910 	o->pack->fold_selection();
2911     }
2912   }
2913 
History_cb_Merge(Fl_Widget * m,void *)2914   void History_cb_Merge(Fl_Widget* m , void*) {
2915     if (m && m->parent()){
2916       History_Pack * hp = dynamic_cast<History_Pack *>(Fl::focus());
2917       if (!hp)
2918 	hp=get_history_pack(xcas::Xcas_input_focus);
2919       if (hp){
2920 	int a=hp->_sel_begin,b= hp->_sel_end;
2921 	if (a>=0 && b>=0){
2922 	  string s;
2923 	  int m=min(a,b),M=max(a,b);
2924 	  int w=hp->child(min(m,hp->children()-1))->w();
2925 	  for (int i=m;i<=M;++i){
2926 	    s += hp->value(m);
2927 	    if (!s.empty() && s[s.size()-1]!=';')
2928 	      s += ';';
2929 	    if (i!=M)
2930 	      s += '\n';
2931 	    Fl_Widget * wid= hp->child(m);
2932 	    hp->add_history_map(wid,hp->undo_position);
2933 	    hp->remove(wid);
2934 	    delete wid;
2935 	  }
2936 	  Multiline_Input_tab * mi = dynamic_cast<Multiline_Input_tab *>(new_question_multiline_input(w,(3+hp->labelsize())*(M-m+1)));
2937 	  hp->add_entry(m,mi);
2938 	  mi->value(s.c_str());
2939 	  mi->set_changed();
2940 	  hp->_sel_begin=hp->_sel_end=m;
2941 	  parent_redraw(hp);
2942 	}
2943       }
2944     }
2945   }
2946 
History_cb_Flatten(Fl_Widget * m,void *)2947   void History_cb_Flatten(Fl_Widget* m , void*) {
2948     if (m && m->parent()){
2949       History_Fold * o = get_history_fold_focus(m);
2950       if (o)
2951 	o->pack->flatten();
2952     }
2953   }
2954 
cb_New_Input(Fl_Widget * m,void *)2955   void cb_New_Input(Fl_Widget* m , void*) {
2956     Fl_Widget * w = xcas::Xcas_input_focus;
2957     if (dynamic_cast<Xcas_Text_Editor *>(w) || !dynamic_cast<Fl_Group *>(w))
2958       w=parent_skip_scroll(parent_skip_scroll(w));
2959     History_Pack * hp=dynamic_cast<History_Pack *>(w);
2960     History_Fold * o = get_history_fold_focus(m);
2961     if (hp && o && !get_history_pack(hp->parent()))
2962       hp=0;
2963     if (!hp && m && m->parent()){
2964       if (o)
2965 	hp=o->pack;
2966     }
2967     if (hp){
2968       // hp->_sel_begin=-1;
2969       hp->set_sel_begin(xcas::Xcas_input_focus);
2970       hp->add_entry(hp->_sel_begin);
2971     }
2972   }
2973 
History_cb_New_Xcas_Text_Editor(Fl_Widget * m,void *)2974   void History_cb_New_Xcas_Text_Editor(Fl_Widget* m , void*) {
2975     if (m && m->parent()){
2976       History_Fold * o = get_history_fold_focus(m);
2977       if (o){
2978 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
2979 	Fl_Widget * e=new_question_editor(max(o->pack->w()-o->pack->_printlevel_w,1),editor_hsize(o->pack));
2980 	if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(e)){
2981 	  ed->Fl_Text_Display::textsize(o->labelsize());
2982 	  vector<Fl_Text_Display::Style_Table_Entry> & v=ed->styletable;
2983 	  for (unsigned i=0;i<v.size();++i)
2984 	    v[i].size=o->labelsize();
2985 	}
2986 	change_group_fontsize(e,o->labelsize());
2987 	o->pack->add_entry(o->pack->_sel_begin,e);
2988 	if (Keyboard_Switch)
2989 	  Keyboard_Switch(0x8000 | 0x1);
2990       }
2991     }
2992   }
2993 
History_cb_New_Equation(Fl_Widget * m,void *)2994   void History_cb_New_Equation(Fl_Widget* m , void*) {
2995     if (m && m->parent()){
2996       History_Fold * o = get_history_fold_focus(m);
2997       if (o){
2998 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
2999 	Fl_Widget * e=new_question_equation(max(o->pack->w()-o->pack->_printlevel_w,1),o->pack->labelsize()+10);
3000 	change_group_fontsize(e,o->labelsize());
3001 	if (Equation * eq=dynamic_cast<Equation *>(e))
3002 	  eq->select();
3003 	o->pack->add_entry(o->pack->_sel_begin,e);
3004 	if (Keyboard_Switch)
3005 	  Keyboard_Switch(0x8000 | 0x1);
3006       }
3007     }
3008   }
3009 
new_tableur(Fl_Widget * m,bool load)3010   void new_tableur(Fl_Widget * m,bool load){
3011     if (m && m->parent()){
3012       History_Fold * o = get_history_fold_focus(m);
3013       if (o){
3014 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3015 	int pos=o->pack->_sel_begin;
3016 	Fl_Widget * e=new_tableur(max(o->pack->w()-o->pack->_printlevel_w,1),max(o->h()-4*o->labelsize(),200),o->pack);
3017 	change_group_fontsize(e,o->labelsize());
3018 	o->pack->add_entry(pos,e);
3019 	Tableur_Group * t =dynamic_cast<Tableur_Group *>(e);
3020 	if (t){
3021 	  context * contextptr=get_context(o);
3022 	  if (load){
3023 	    string s(tableur_insert(t->table));
3024 	    if (!s.empty()){
3025 	      gen tmp(s,contextptr);
3026 	      if (tmp.type==_IDNT){
3027 		t->table->name=tmp;
3028 		if (t->table->filename)
3029 		  delete t->table->filename;
3030 		if ( (t->table->filename = new string(tmp.print(contextptr)+".tab"))){
3031 		  t->fname->label(t->table->filename->c_str());
3032 		  t->fname->redraw();
3033 		}
3034 		t->table->update_status();
3035 	      }
3036 	    }
3037 	  }
3038 	  else
3039 	    if (!t->table->filename)
3040 	      t->table->config();
3041 	  t->table->row(0);
3042 	  t->table->col(0);
3043 	  t->table->_goto->value("A0");
3044 	  if (t->table->rows() && t->table->cols()){
3045 	    gen tmp=t->table->m[0][0];
3046 	    if (tmp.type==_VECT && tmp._VECTptr->size()==3)
3047 	      tmp=tmp._VECTptr->front();
3048 	    t->table->input->value(tmp.print(contextptr).c_str(),true);
3049 	  }
3050 	}
3051       }
3052     }
3053   }
3054 
History_cb_New_Tableur(Fl_Widget * m,void *)3055   void History_cb_New_Tableur(Fl_Widget* m , void*) {
3056     new_tableur(m,false);
3057   }
3058 
History_cb_Insert_Tableur(Fl_Widget * m,void *)3059   void History_cb_Insert_Tableur(Fl_Widget* m , void*) {
3060     new_tableur(m,true);
3061   }
3062 
History_cb_New_Comment_Input(Fl_Widget * m,void *)3063   void History_cb_New_Comment_Input(Fl_Widget* m , void*) {
3064     if (m && m->parent()){
3065       History_Fold * o = get_history_fold_focus(m);
3066       if (o){
3067 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3068 	Fl_Widget * e=new_comment_input(max(o->pack->w()-o->pack->_printlevel_w,1),o->labelsize()+10);
3069 	change_group_fontsize(e,o->labelsize());
3070 	o->pack->add_entry(o->pack->_sel_begin,e);
3071       }
3072     }
3073   }
3074 
new_program(Fl_Widget * m,bool load)3075   void new_program(Fl_Widget * m, bool load){
3076     if (m && m->parent()){
3077       History_Fold * o = get_history_fold_focus(m);
3078       if (o){
3079 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3080 	int pos=o->pack->_sel_begin;
3081 	Fl_Widget * e=new_program(max(o->pack->w()-o->pack->_printlevel_w,1),o->h()/2,o->pack);
3082 	change_group_fontsize(e,o->labelsize());
3083 	o->pack->add_entry(pos,e);
3084 	if (Editeur * ed=dynamic_cast<Editeur *>(e)){
3085 	  if (load){
3086 	    string s=editeur_load(ed->editor);
3087 	    if (!s.empty()){
3088 	      ed->editor->label(s.c_str());
3089 	      ed->output->value(remove_path(s).c_str());
3090 	      ed->output->redraw();
3091 	    }
3092 	  }
3093 	  else
3094 	    cb_choose_func(ed->editor);
3095 	  // else ed->editor->buffer()->insert(0,"\n:;");
3096 	  Fl::focus(ed->editor);
3097 	}
3098       }
3099     }
3100   }
3101 
History_cb_New_Program(Fl_Widget * m,void *)3102   void History_cb_New_Program(Fl_Widget* m , void*) {
3103     new_program(m,false);
3104   }
3105 
History_cb_Insert_Program(Fl_Widget * m,void *)3106   void History_cb_Insert_Program(Fl_Widget* m , void*) {
3107     new_program(m,true);
3108   }
3109 
new_figure(Fl_Widget * m,bool load,bool dim3,bool approx=true)3110   void new_figure(Fl_Widget * m,bool load,bool dim3,bool approx=true){
3111     if (m && m->parent()){
3112       History_Fold * o = get_history_fold_focus(m);
3113       if (o){
3114 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3115 	int pos=o->pack->_sel_begin;
3116 	Fl_Widget * e=new_figure(max(o->pack->w()-o->pack->_printlevel_w,1),max(4*o->h()/5,340),o->pack,dim3,approx);
3117 	change_group_fontsize(e,o->labelsize());
3118 	o->pack->add_entry(pos,e);
3119 	if (Figure * f=dynamic_cast<Figure *>(e)){
3120 	  if (load){
3121 	    string s=figure_insert(f);
3122 	    f->rename(remove_path(s));
3123 	  }
3124 	  else {
3125 	    // f->geo->set_mode(0,0,1);
3126 	    // f->mode->value("point");
3127 	  }
3128 	}
3129       }
3130     }
3131   }
3132 
History_cb_New_Figure(Fl_Widget * m,void *)3133   void History_cb_New_Figure(Fl_Widget* m , void*) {
3134     new_figure(m,false,false,true);
3135   }
3136 
History_cb_New_Figurex(Fl_Widget * m,void *)3137   void History_cb_New_Figurex(Fl_Widget* m , void*) {
3138     new_figure(m,false,false,false);
3139   }
3140 
History_cb_Insert_Figure(Fl_Widget * m,void *)3141   void History_cb_Insert_Figure(Fl_Widget* m , void*) {
3142     new_figure(m,true,false,true);
3143   }
3144 
History_cb_New_Figure3d(Fl_Widget * m,void *)3145   void History_cb_New_Figure3d(Fl_Widget* m , void*) {
3146     new_figure(m,false,true,true);
3147   }
3148 
History_cb_New_Figure3dx(Fl_Widget * m,void *)3149   void History_cb_New_Figure3dx(Fl_Widget* m , void*) {
3150     new_figure(m,false,true,false);
3151   }
3152 
History_cb_New_Logo(Fl_Widget * m,void *)3153   void History_cb_New_Logo(Fl_Widget* m , void*) {
3154     if (m && m->parent()){
3155       History_Fold * o = get_history_fold_focus(m);
3156       if (o){
3157 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3158 	int pos=o->pack->_sel_begin;
3159 	Fl_Widget * e=new_logo(max(o->pack->w()-o->pack->_printlevel_w,1),2*o->h()/3,o->pack);
3160 	change_group_fontsize(e,o->labelsize());
3161 	o->pack->add_entry(pos,e);
3162       }
3163     }
3164   }
3165 
History_cb_New_HF(Fl_Widget * m,void *)3166   void History_cb_New_HF(Fl_Widget* m , void*) {
3167     if (m && m->parent()){
3168       History_Fold * o = get_history_fold_focus(m);
3169       if (o){
3170 	o->pack->set_sel_begin(xcas::Xcas_input_focus);
3171 	int pos=o->pack->_sel_begin;
3172 	Fl_Group::current(o->pack);
3173 	History_Fold * e=new History_Fold(0,0,max(o->pack->w()-o->pack->_printlevel_w,1),4*o->labelsize());
3174 	if (e){
3175 	  e->pack->_select=o->pack->_select;
3176 	  e->pack->_insert=o->pack->_insert;
3177 	  e->pack->new_question=o->pack->new_question;
3178 	  e->pack->_spacing=o->pack->_spacing;
3179 	  e->pack->eval=o->pack->eval;
3180 	  e->pack->add_entry(-1);
3181 	  e->pack->_resize_above=true;
3182 	  e->pack->contextptr=o->pack->contextptr;
3183 	  change_group_fontsize(e,o->labelsize());
3184 	  o->pack->add_entry(pos,e);
3185 	}
3186       }
3187     }
3188   }
3189 
cb_Delete(Fl_Widget * m,void *)3190   void cb_Delete(Fl_Widget* m , void*) {
3191     History_Pack * hp=0;
3192     History_Fold * o=0;
3193     if ( (hp=dynamic_cast<History_Pack *>(Fl::focus())) )
3194       ;
3195     else
3196       if (m && m->parent()){
3197 	o = get_history_fold_focus(m);
3198 	if (o)
3199 	  hp = o->pack;
3200       }
3201     if (hp)
3202       hp->remove_selected_levels(false);
3203   }
3204 
update(int n)3205   void History_Pack::update(int n){
3206     if (n<0)
3207       n=0;
3208     if (eval_below && n<children()){
3209       Fl_Group * hp0g = dynamic_cast<Fl_Group *>(child(n));
3210       if (History_Fold * hf=dynamic_cast<History_Fold *>(hp0g)){
3211 	hf->eval();
3212 	return;
3213       }
3214       if (Logo * l=dynamic_cast<Logo *>(hp0g)){
3215 	if (l->hp){
3216 	  l->hp->eval_below=true;
3217 	  l->hp->eval_next=true;
3218 	  l->hp->update(0);
3219 	}
3220 	return;
3221       }
3222       if (Figure * f=dynamic_cast<Figure *>(hp0g))
3223 	f->geo->hp->eval_next=true;
3224       if (hp0g && hp0g->children())
3225 	History_Pack_cb_eval(hp0g->child(0),0);
3226     }
3227   }
3228 
next(int hp_pos)3229   void History_Pack::next(int hp_pos){
3230     int hp_n=children();
3231     ++hp_pos;
3232     if (hp_pos<hp_n)
3233       update(hp_pos);
3234     else {
3235       next_delay=0;
3236       // Check for a Graphic child in parent, update it
3237       Fl_Group * hpp = parent_skip_scroll(this);
3238       bool nextup=eval_next;
3239       if (hpp){
3240 	int N=hpp->children();
3241 	for (int i=0;i<N;++i){
3242 	  Graph2d3d * geo = dynamic_cast<Graph2d3d *>(hpp->child(i));
3243 	  if (!geo){
3244 	    Fl_Window * win = dynamic_cast<Fl_Window *>(hpp->child(i));
3245 	    if (win)
3246 	      geo=dynamic_cast<Graph2d3d *>(win->child(0));
3247 	  }
3248 	  if (geo){
3249 	    geo->update(this,update_pos>=0?update_pos:0);
3250 	    geo->no_handle=false;
3251 	    if (update_pos>=0 && update_pos<children())
3252 	      set_scroller(dynamic_cast<Fl_Group *>(child(update_pos)));
3253 	  }
3254 	}
3255       }
3256       if (eval_below_once)
3257 	eval_below=false;
3258       if (eval_below ){
3259 	if (queue_pos>=0 && queue_pos<hp_n){
3260 	  update_pos=queue_pos;
3261 	  queue_pos=-1;
3262 	  set_gen_value(update_pos,queue_val,true);
3263 	  nextup=false;
3264 	}
3265       }
3266       if (nextup){
3267 	eval_next=false;
3268 	// check if parent history_pack recomputes
3269 	int posup;
3270 	History_Pack * hpup= get_history_pack(hpp,posup);
3271 	if (hpup)
3272 	  hpup->next(posup);
3273       }
3274     }
3275   }
3276 
History_cb_Run_Worksheet(Fl_Widget * m,void *)3277   void History_cb_Run_Worksheet(Fl_Widget* m , void*) {
3278     if (m && m->parent()){
3279       History_Fold * o = get_history_fold(m);
3280       if (o) o->eval();
3281     }
3282   }
3283 
History_cb_Run_Below(Fl_Widget * m,void *)3284   void History_cb_Run_Below(Fl_Widget* m , void*) {
3285     if (m && m->parent()){
3286       History_Fold * o = get_history_fold_focus(m);
3287       if (o ){
3288 	int n=o->pack->children(),i=n;
3289 	o->pack->eval_below=true;
3290 	Fl_Widget * w =xcas::Xcas_input_focus;
3291 	for (;w;){
3292 	  i=o->pack->find(w);
3293 	  if (i!=n)
3294 	    break;
3295 	  w=w->parent();
3296 	}
3297 	if (i<n){
3298 	  Fl_Group * g = dynamic_cast<Fl_Group *>(o->pack->child(i));
3299 	  if (g && !dynamic_cast<Figure *>(g) && g->children())
3300 	    History_Pack_cb_eval(g->child(0),0);
3301 	}
3302       }
3303     }
3304   }
3305 
3306   // Model callback function (not used!)
History_cb_(Fl_Widget * m,void *)3307   void History_cb_(Fl_Widget* m , void*) {
3308     if (m && m->parent()){
3309       History_Fold * o = get_history_fold_focus(m);
3310       if (o ){
3311       }
3312     }
3313   }
3314 
cb_Rm_Answers(History_Fold * o,int i)3315   void cb_Rm_Answers(History_Fold * o,int i){
3316     if (!o)
3317       return;
3318     int n=o->pack->children();
3319     for (;i<n;++i){
3320       Fl_Group * g = dynamic_cast<Fl_Group *>(o->pack->child(i));
3321       if (History_Fold * hf=dynamic_cast<History_Fold *>(g)){
3322 	cb_Rm_Answers(hf,0);
3323 	continue;
3324       }
3325       int c=g->children();
3326       bool is_input=dynamic_cast<Multiline_Input_tab *>(g->child(0));
3327       bool is_equation=dynamic_cast<Equation *>(g->child(0));
3328       bool is_editor=dynamic_cast<Xcas_Text_Editor *>(g->child(0));
3329       if (g && c>=2 && (is_input || is_equation || is_editor)){
3330 	for (int j=c-1;j;--j)
3331 	  g->remove(g->child(j));
3332 	g->resize(g->x(),g->y(),g->w(),g->child(0)->h());
3333 	o->redraw();
3334       }
3335     }
3336   }
3337 
cb_Rm_Answers(Fl_Widget * m,void *)3338   void cb_Rm_Answers(Fl_Widget* m , void*) {
3339     if (m && m->parent()){
3340       History_Fold * o = get_history_fold_focus(m);
3341       if (o){
3342 	int n=o->pack->children(),i=n;
3343 	Fl_Widget * w =xcas::Xcas_input_focus;
3344 	for (;w;){
3345 	  if (w->parent()==o->pack){
3346 	    i=o->pack->find(w);
3347 	    break;
3348 	  }
3349 	  w=w->parent();
3350 	}
3351 	cb_Rm_Answers(o,i);
3352       }
3353     }
3354   }
3355 
xdvi(const std::string & name)3356   void xdvi(const std::string & name){
3357     string s=remove_extension(name);
3358 #ifdef WIN32
3359     system_no_deprecation((xcasroot()+"latex.bat "+s).c_str());
3360     cerr << xcasroot()+"latex.bat "+s << '\n';
3361     system_no_deprecation((xcasroot()+"xdvi.bat "+s+" &").c_str());
3362     cerr << xcasroot()+"xdvi.bat "+s+" &" << '\n';
3363 #else
3364     string path=get_path(s);
3365     s=remove_path(s);
3366     if (path.empty()){
3367       char buf[1024];
3368       path=getcwd(buf,1024);
3369     }
3370     int tmpresult=system_no_deprecation(("cd "+path+" ; latex "+s+" ").c_str());
3371     tmpresult=system_no_deprecation(("cd "+path+" ; xdvi "+s+" &").c_str());
3372     tmpresult=system_no_deprecation(("cd "+path+" ; dvips "+s+" -o "+s+".ps && pstopnm -stdout "+s+" | pnmtopng > "+s+".png").c_str());
3373     fl_message("%s",("->"+s+".tex/.dvi/.ps/.png").c_str());
3374 #endif //
3375   }
3376 
dvips(const std::string & name)3377   void dvips(const std::string & name){
3378 #ifdef WIN32
3379     system_no_deprecation((xcasroot()+"latex.bat "+remove_extension(name)).c_str());
3380     system_no_deprecation((xcasroot()+"dvips.bat "+remove_extension(name)+" &").c_str());
3381 #else
3382     string s=remove_extension(name);
3383     string path=get_path(s);
3384     s=remove_path(s);
3385     int tmpresult=system_no_deprecation(("cd "+path+" ; latex "+s+" ").c_str());
3386     tmpresult=system_no_deprecation(("cd "+path+" ; dvips "+s+" -o "+s+".ps && pstopnm -stdout "+s+" | pnmtopng > "+s+".png").c_str());
3387 #endif //
3388   }
3389 
file2stream(const char * filename,ostream & texof)3390   void file2stream(const char * filename,ostream & texof){
3391     // copy f to the current stream and remove
3392     FILE * f=fopen(filename,"r");
3393     for (;f;){
3394       char ch=fgetc(f);
3395       if (feof(f))
3396 	break;
3397       texof << ch;
3398     }
3399     fclose(f);
3400     unlink(filename);
3401   }
3402 
historypack2tex(Fl_Widget * wid,int level,ostream & texof,History_Pack * pack,const std::string & name,int & number)3403   void historypack2tex(Fl_Widget * wid,int level,ostream & texof,History_Pack * pack,const std::string & name,int & number){
3404     // const giac::context * contextptr = get_context(wid);
3405     static unsigned count=0;
3406     if (dynamic_cast<Figure *>(wid))
3407       texof << "\\\\" << '\n';
3408     if (Fl_Group * g = dynamic_cast<Fl_Group *>(wid)){
3409       if (!g || !g->children())
3410 	return;
3411       bool folded=false;
3412       if (History_Fold * hf = dynamic_cast<History_Fold *>(wid))
3413 	folded=hf->folded();
3414       if (folded)
3415 	texof << "%% begin hidden group" << '\n';
3416       int jmax=g->children();
3417       for (int j=0;j<jmax;j++){
3418 	Fl_Widget * wid = g->child(j);
3419 	historypack2tex(wid,level,texof,pack,name,number);
3420       }
3421       if (folded)
3422 	texof << "%% end hidden group" << '\n';
3423     }
3424     if (Multiline_Input_tab * i =dynamic_cast<Multiline_Input_tab *>(wid)){
3425       texof << "{\\tt " << translate_underscore(i->value()) << " } \\\\" << '\n';
3426       return;
3427     }
3428     if (Editeur * ed=dynamic_cast<Editeur *>(wid)){
3429       texof << '\n' << "\\begin{verbatim}"<<'\n';
3430       texof << ed->value() << '\n';
3431       texof  << "\\end{verbatim}" << '\n';
3432       return;
3433     }
3434     if (Xcas_Text_Editor * ed=dynamic_cast<Xcas_Text_Editor *>(wid)){
3435       texof << "{\\tt " << translate_underscore(ed->value()) << " } \\\\" << '\n';
3436       return;
3437     }
3438     if (const Flv_Table_Gen * t = dynamic_cast<const Flv_Table_Gen *>(wid)){
3439       texof << "\n\\noindent\n" <<spread2tex(t->m,0,pack->contextptr) << '\n' ; // formule
3440       texof << "\n\\noindent\n" << spread2tex(t->m,1,pack->contextptr) << '\n' << '\n' ; // formule
3441       return ;
3442     }
3443     if (Equation * eq=dynamic_cast<Equation *>(wid)){
3444       texof << "\\begin{equation} \\label{eq:" << level << "}" << '\n';
3445       texof << gen2tex(eq->get_data(),pack->contextptr) ;
3446       texof << "\n\\end{equation}" << '\n';
3447       return;
3448     }
3449     if (Fl_Input * i = dynamic_cast<Fl_Input *>(wid)){
3450       string s=i->value();
3451       if (s.empty() || (s.size()>4 && s.substr(0,4)=="pnt("))
3452 	return;
3453       texof << "{\\em " << translate_underscore(s) << "\\/} \\\\\n";
3454       return;
3455     }
3456     if (Graph2d * g=dynamic_cast<Graph2d *>(wid)){
3457       double xunit=giac::horiz_latex/(g->window_xmax-g->window_xmin);
3458       double yunit=giac::vert_latex/(g->window_ymax-g->window_ymin);
3459       string filename="#g2"+print_INT_(count);
3460       ++count;
3461       FILE * f=fopen(filename.c_str(),"w");
3462       if (f){
3463 	graph2tex(f,g->plot_instructions,g->window_xmin,g->window_xmax,g->window_ymin,g->window_ymax,xunit,yunit,filename.c_str(),false,get_context(g));
3464 	fclose(f);
3465 	file2stream(filename.c_str(),texof); // copy f to the current stream
3466       }
3467       return;
3468     }
3469     if (Graph3d * g=dynamic_cast<Graph3d *>(wid)){
3470       /*
3471       double xunit=giac::horiz_latex/(g->window_xmax-g->window_xmin);
3472       double yunit=giac::vert_latex/(g->window_ymax-g->window_ymin);
3473       string filename="#g3"+print_INT_(unsigned(g));
3474       FILE * f=fopen(filename.c_str(),"w");
3475       if (f){
3476 	int gw=g->w();
3477 	g->resize(g->x(),g->y(),400,g->h());
3478 	fprintf(f,"\n\n{\n\\setlength{\\unitlength}{1pt}\n\\begin{picture}(%d,%d)(%d,%d)\n{\\special{\"\n",g->w(),g->h(),0,0);
3479 	g->printing=f;
3480 	g->print(contextptr);
3481 	g->printing=0;
3482 	g->resize(g->x(),g->y(),gw,g->h());
3483 	fprintf(f,"%s","}\n}\\end{picture}\n}\n\n");
3484 	fclose(f);
3485 	file2stream(filename.c_str(),texof);
3486       }
3487       */
3488       ++number;
3489       string filename=remove_extension(name)+print_INT_(number)+".eps";
3490       FILE * f=fopen(filename.c_str(),"w");
3491       if (f){
3492 	texof <<  "\\includegraphics[bb=0 0 400 "<< g->h() <<"]{" << filename << "}" << '\n' << '\n' ;
3493 	int gw=g->w();
3494 	g->resize(g->x(),g->y(),400,g->h());
3495 	g->printing=f;
3496 	g->print();
3497 	g->printing=0;
3498 	g->resize(g->x(),g->y(),gw,g->h());
3499 	fclose(f);
3500       }
3501       return;
3502     }
3503     if (Turtle * g=dynamic_cast<Turtle *>(wid)){
3504       double xunit=giac::horiz_latex/g->w();
3505       double yunit=giac::vert_latex/g->h();
3506       string filename="#t"+print_INT_(count);
3507       ++count;
3508       FILE * f=fopen(filename.c_str(),"w");
3509       if (f && g->turtleptr){
3510 	graph2tex(f,turtlevect2vecteur(*g->turtleptr),0,g->w(),0,g->h(),xunit,yunit,filename.c_str(),true,get_context(g));
3511 	fclose(f);
3512 	file2stream(filename.c_str(),texof); // copy f to the current stream
3513       }
3514       return;
3515     }
3516   }
3517 
history_pack_selection(History_Pack * hp,int & m,int & M)3518   void history_pack_selection(History_Pack * hp, int & m,int & M){
3519     int l=hp->children();
3520     m=std::min(hp->_sel_begin,hp->_sel_end+1);
3521     M=std::max(hp->_sel_begin,hp->_sel_end+1);
3522     m=std::max(m,0);
3523     M=std::min(M,l);
3524   }
3525 
historypack2tex(History_Pack * hp,const std::string & name,ostream & texof,bool selection)3526   void historypack2tex(History_Pack * hp,const std::string & name,ostream & texof,bool selection){
3527     int l=hp->children();
3528     int m=0,M=l;
3529     int number=1;
3530     if (selection)
3531       history_pack_selection(hp,m,M);
3532     for (int i=m;i<M;++i){
3533       if (!texof)
3534 	return;
3535       texof << "\\noindent \\framebox{"<<i+1<<"} ";
3536       historypack2tex(hp->child(i),i,texof,hp,name,number);
3537     }
3538   }
3539 
historypack2tex(History_Pack * hp,const std::string & name,bool texheader,bool selection)3540   void historypack2tex(History_Pack * hp,const std::string & name,bool texheader,bool selection){
3541     ofstream texof(name.c_str());
3542     if (!texof)
3543       return;
3544     if (texheader){
3545       texof << "% Generated by xcas" << '\n';
3546       texof << giac::tex_preamble ;
3547     }
3548     historypack2tex(hp,name,texof,selection);
3549     if (texheader)
3550       texof << giac::tex_end << '\n';
3551     texof.close();
3552   }
3553 
historypack2tex(History_Pack * hp,bool texheader,bool selection=false)3554   string historypack2tex(History_Pack * hp,bool texheader,bool selection=false){
3555     string name;
3556     static int i=0;
3557     ++i;
3558     if (hp->url)
3559       name=remove_extension(*hp->url)+".tex";
3560     else
3561       name="session"+print_INT_(i)+".tex";
3562     historypack2tex(hp,name,texheader,selection);
3563     return name;
3564   }
3565 
3566 
history_pack_latex_print(Fl_Widget * m,bool preview,bool selection)3567   void history_pack_latex_print(Fl_Widget* m ,bool preview,bool selection){
3568     if (m && m->parent()){
3569       History_Fold * o = get_history_fold(m);
3570       if (o){
3571 	string s=historypack2tex(o->pack,true,selection);
3572 	if (preview)
3573 	  xdvi(s);
3574 	else
3575 	  dvips(s);
3576       }
3577     }
3578   }
3579 
History_cb_LaTeX_Preview(Fl_Widget * m,void *)3580   void History_cb_LaTeX_Preview(Fl_Widget* m , void*) {
3581     history_pack_latex_print(m,true,false);
3582   }
3583 
History_cb_LaTeX_Preview_sel(Fl_Widget * m,void *)3584   void History_cb_LaTeX_Preview_sel(Fl_Widget* m , void*) {
3585     history_pack_latex_print(m,true,true);
3586   }
3587 
History_cb_LaTeX_Print(Fl_Widget * m,void *)3588   void History_cb_LaTeX_Print(Fl_Widget* m , void*) {
3589     history_pack_latex_print(m,false,false);
3590   }
3591 
History_cb_LaTeX_Print_sel(Fl_Widget * m,void *)3592   void History_cb_LaTeX_Print_sel(Fl_Widget* m , void*) {
3593     history_pack_latex_print(m,false,true);
3594   }
3595 
History_cb_Print(Fl_Widget * m,void *)3596   void History_cb_Print(Fl_Widget* m , void*) {
3597     if (m && m->parent()){
3598       History_Fold * o = get_history_fold(m);
3599       if (o)
3600 	widget_print(o->pack);
3601     }
3602   }
3603 
3604 
History_cb_Preview(Fl_Widget * m,void *)3605   void History_cb_Preview(Fl_Widget* m , void*) {
3606     if (m && m->parent()){
3607       History_Fold * o = get_history_fold(m);
3608       if (o)
3609 	widget_ps_print(o->pack,o->pack->url?*o->pack->url:"session",false,0,true);
3610     }
3611   }
3612 
History_cb_Preview_selected(Fl_Widget * m,void *)3613   void History_cb_Preview_selected(Fl_Widget* m , void*) {
3614     if (m && m->parent()){
3615       History_Fold * o = get_history_fold(m);
3616       if (o){
3617 	int i=o->pack->_sel_begin,j=o->pack->_sel_end;
3618 	if (i>j)
3619 	  std::swap(i,j);
3620 	if (i<0)
3621 	  i=0;
3622 	if (j<0)
3623 	  return;
3624 	int n=o->pack->children();
3625 	for (;i<=j && i<n;++i)
3626 	  widget_ps_print(o->pack->child(i),("session"+print_INT_(i)).c_str(),true);
3627       }
3628     }
3629   }
3630 
fl_handle(Fl_Widget * w)3631   void fl_handle(Fl_Widget * w){
3632     if (fl_handle_lock)
3633       return;
3634     fl_handle_lock=true;
3635     Fl::focus(w);
3636     Fl::flush();
3637     Fl::handle(FL_KEYBOARD,w->window());
3638     Fl::flush();
3639     fl_handle_lock=false;
3640   }
3641 
History_cb_Newline(Fl_Widget * m,void *)3642   void History_cb_Newline(Fl_Widget* m , void*) {
3643     if (fl_handle_lock)
3644       return;
3645     static char petit_buffer[2];
3646     petit_buffer[0]='\n';
3647     petit_buffer[1]=0;
3648     Fl::e_text= petit_buffer;
3649     Fl::e_length=1;
3650     Fl::e_keysym='\n';
3651     fl_handle(xcas::Xcas_input_focus);
3652   }
3653 
3654 
cb_Paste(Fl_Widget * m,void *)3655   void cb_Paste(Fl_Widget* m , void*){
3656     Fl_Widget * w=Fl::focus();
3657     if (w){
3658       if (Flv_Table_Gen * spread_ptr=dynamic_cast<Flv_Table_Gen *> (w)){
3659 	spread_ptr->paste(spread_ptr->selected);
3660       }
3661       else
3662 	Fl::paste(*w);
3663     }
3664   }
3665 
synchronize(const History_Pack * hp,Graph2d3d * geo)3666   void synchronize(const History_Pack * hp,Graph2d3d * geo){
3667     geo->clear();
3668     int s=hp->children();
3669     for (int i=0;i<s;++i){
3670       Fl_Widget * wid=hp->child(i);
3671       if (Fl_Group * gr=dynamic_cast<Fl_Group *>(wid)){
3672 	if (gr->children()>=3){
3673 	  wid=gr->child(2);
3674 	  if (Fl_Scroll * scroll = dynamic_cast<Fl_Scroll *>(wid))
3675 	    wid=scroll->child(0);
3676 	  if (Gen_Output * out=dynamic_cast<Gen_Output *>(wid)){
3677 	    geo->add(out->value());
3678 	    continue;
3679 	  }
3680 	}
3681       }
3682       geo->add(undef);
3683     }
3684   }
3685 
History_cb_Undo(Fl_Widget * m,void *)3686   void History_cb_Undo(Fl_Widget* m , void*) {
3687     if (m && m->parent()){
3688       Figure * f=find_figure(m);
3689       if (f && f->geo){
3690 	f->geo->hp->restore(-1);
3691 	synchronize(f->geo->hp,f->geo);
3692       }
3693       else {
3694 	History_Pack * o = get_history_pack(m);
3695 	if (o){
3696 	  o->restore(-1);
3697 	  return;
3698 	}
3699 	History_Fold * hf = get_history_fold(m);
3700 	if (hf)
3701 	  hf->pack->restore(-1);
3702       }
3703     }
3704   }
3705 
History_cb_Redo(Fl_Widget * m,void *)3706   void History_cb_Redo(Fl_Widget* m , void*) {
3707     if (m && m->parent()){
3708       Figure * f=find_figure(m);
3709       if (f && f->geo){
3710 	f->geo->hp->restore(1);
3711 	synchronize(f->geo->hp,f->geo);
3712       }
3713       else {
3714 	History_Pack * o = get_history_pack(m);
3715 	if (o){
3716 	  o->restore(1);
3717 	  return;
3718 	}
3719 	History_Fold * hf = get_history_fold(m);
3720 	if (hf)
3721 	  hf->pack->restore(1);
3722       }
3723     }
3724   }
3725 
3726   Fl_Menu_Item History_menu[] = {
3727     {gettext("File"), 0,  0, 0, 64, 0, 0, 14, 56},
3728     {gettext("Save"), 0,  (Fl_Callback*)History_cb_Save, 0, 0, 0, 0, 14, 56},
3729     {gettext("Save as"), 0,  (Fl_Callback*)History_cb_Save_as, 0, 0, 0, 0, 14, 56},
3730     {gettext("Export as"), 0,  0, 0, 64, 0, 0, 14, 56},
3731     {gettext("xcas text"), 0,  (Fl_Callback*)History_cb_Save_as_xcas_text, 0, 0, 0, 0, 14, 56},
3732     {gettext("maple text"), 0,  (Fl_Callback*)History_cb_Save_as_maple_text, 0, 0, 0, 0, 14, 56},
3733     {gettext("mupad text"), 0,  (Fl_Callback*)History_cb_Save_as_mupad_text, 0, 0, 0, 0, 14, 56},
3734     {gettext("ti text"), 0,  (Fl_Callback*)History_cb_Save_as_ti_text, 0, 0, 0, 0, 14, 56},
3735     {0},
3736     {gettext("Load"), 0x8006c,  (Fl_Callback*)History_cb_Load, 0, 0, 0, 0, 14, 56},
3737     {gettext("Insert"), 0,  0, 0, 64, 0, 0, 14, 56},
3738     {gettext("xcas session"), 0,  (Fl_Callback*)History_cb_Insert, 0, 0, 0, 0, 14, 56},
3739     {gettext("figure"), 0,  (Fl_Callback*)History_cb_Insert_Figure, 0, 0, 0, 0, 14, 56},
3740     {gettext("spreadsheet"), 0,  (Fl_Callback*)History_cb_Insert_Tableur, 0, 0, 0, 0, 14, 56},
3741     {gettext("program"), 0,  (Fl_Callback*)History_cb_Insert_Program, 0, 0, 0, 0, 14, 56},
3742     {0},
3743     {gettext("Kill"), 0x40071,  (Fl_Callback*)History_cb_Kill, 0, 0, 0, 0, 14, 56},
3744     {gettext("Print"), 0,  0, 0, 64, 0, 0, 14, 56},
3745     {gettext("preview"), 0,  (Fl_Callback*)History_cb_Preview, 0, 0, 0, 0, 14, 56},
3746     {gettext("to printer"), 0,  (Fl_Callback*)History_cb_Print, 0, 0, 0, 0, 14, 56},
3747     {gettext("preview selected levels"), 0,  (Fl_Callback*)History_cb_Preview_selected, 0, 0, 0, 0, 14, 56},
3748     {gettext("latex preview"), 0,  (Fl_Callback*)History_cb_LaTeX_Preview, 0, 0, 0, 0, 14, 56},
3749     {gettext("latex print"), 0,  (Fl_Callback*)History_cb_LaTeX_Print, 0, 0, 0, 0, 14, 56},
3750     {gettext("latex preview selection"), 0,  (Fl_Callback*)History_cb_LaTeX_Preview_sel, 0, 0, 0, 0, 14, 56},
3751     {gettext("latex print selection"), 0,  (Fl_Callback*)History_cb_LaTeX_Print_sel, 0, 0, 0, 0, 14, 56},
3752     {0},
3753     {0},
3754     {gettext("Edit"), 0,  0, 0, 64, 0, 0, 14, 56},
3755     {gettext("Add"), 0,  0, 0, 64, 0, 0, 14, 56},
3756 #ifdef IPAQ
3757     {gettext("comment"), 0,  (Fl_Callback *) History_cb_New_Comment_Input, 0, 0, 0, 0, 14, 56},
3758     {gettext("entry"), 0,  (Fl_Callback *) cb_New_Input, 0, 0, 0, 0, 14, 56},
3759     {gettext("expression"), 0x80065,  (Fl_Callback *) History_cb_New_Equation, 0, 0, 0, 0, 14, 56},
3760     {gettext("syntax colored entry"), 0x80065,  (Fl_Callback *) History_cb_New_Xcas_Text_Editor, 0, 0, 0, 0, 14, 56},
3761     {gettext("spreadsheet"), 0,  (Fl_Callback *) History_cb_New_Tableur, 0, 0, 0, 0, 14, 56},
3762     {gettext("graph, geo2d"), 0,  (Fl_Callback *) History_cb_New_Figure, 0, 0, 0, 0, 14, 56},
3763     {gettext("graph, geo3d"), 0,  (Fl_Callback *) History_cb_New_Figure3d, 0, 0, 0, 0, 14, 56},
3764     {gettext("geo2d exact"), 0,  (Fl_Callback *) History_cb_New_Figurex, 0, 0, 0, 0, 14, 56},
3765     {gettext("geo3d exact"), 0,  (Fl_Callback *) History_cb_New_Figure3dx, 0, 0, 0, 0, 14, 56},
3766     {gettext("turtle"), 0,  (Fl_Callback *) History_cb_New_Logo, 0, 0, 0, 0, 14, 56},
3767     {gettext("program"), 0,  (Fl_Callback *) History_cb_New_Program, 0, 0, 0, 0, 14, 56},
3768     {gettext("group"), 0,  (Fl_Callback *) History_cb_New_HF, 0, 0, 0, 0, 14, 56},
3769 #else
3770     {gettext("comment"), 0x80063,  (Fl_Callback *) History_cb_New_Comment_Input, 0, 0, 0, 0, 14, 56},
3771     {gettext("new entry"), 0x8006e,  (Fl_Callback *) cb_New_Input, 0, 0, 0, 0, 14, 56},
3772     {gettext("equation"), 0x80065,  (Fl_Callback *) History_cb_New_Equation, 0, 0, 0, 0, 14, 56},
3773     {gettext("spreadsheet"), 0x80074,  (Fl_Callback *) History_cb_New_Tableur, 0, 0, 0, 0, 14, 56},
3774     {gettext("graph, geo2d"), 0x80067,  (Fl_Callback *) History_cb_New_Figure, 0, 0, 0, 0, 14, 56},
3775     {gettext("graph, geo3d"), 0x80068,  (Fl_Callback *) History_cb_New_Figure3d, 0, 0, 0, 0, 14, 56},
3776     {gettext("geo2d exact"), 0x80078,  (Fl_Callback *) History_cb_New_Figurex, 0, 0, 0, 0, 14, 56},
3777     {gettext("geo3d exact"), 0x80079,  (Fl_Callback *) History_cb_New_Figure3dx, 0, 0, 0, 0, 14, 56},
3778     {gettext("turtle picture"), 0x80064,  (Fl_Callback *) History_cb_New_Logo, 0, 0, 0, 0, 14, 56},
3779     {gettext("program"), 0x80070,  (Fl_Callback *) History_cb_New_Program, 0, 0, 0, 0, 14, 56},
3780     {gettext("group"), 0,  (Fl_Callback *) History_cb_New_HF, 0, 0, 0, 0, 14, 56},
3781 #endif // IPAQ
3782     {0},
3783     {gettext("Execute"), 0,  0, 0, 64, 0, 0, 14, 56},
3784     {gettext("worksheet"), 0,  (Fl_Callback *) History_cb_Run_Worksheet, 0, 0, 0, 0, 14, 56},
3785     {gettext("below"), 0,  (Fl_Callback *) History_cb_Run_Below, 0, 0, 0, 0, 14, 56},
3786     {gettext("remove answers below"), 0,  (Fl_Callback *) cb_Rm_Answers, 0, 0, 0, 0, 14, 56},
3787     {0},
3788     {gettext("Insert newline"), 0,  (Fl_Callback *) History_cb_Newline, 0, 0, 0, 0, 14, 56},
3789     {gettext("Paste"), 0,  (Fl_Callback *) cb_Paste, 0, 0, 0, 0, 14, 56},
3790     {gettext("Delete selected levels"), 0,  (Fl_Callback *) cb_Delete, 0, 0, 0, 0, 14, 56},
3791     {gettext("Group selected levels"), 0,  (Fl_Callback *) History_cb_Fold, 0, 0, 0, 0, 14, 56},
3792     {gettext("Merge selected levels"), 0,  (Fl_Callback *) History_cb_Merge, 0, 0, 0, 0, 14, 56},
3793     {gettext("Degroup current fold"), 0,  (Fl_Callback *) History_cb_Flatten, 0, 0, 0, 0, 14, 56},
3794     {gettext("Undo"), 0,  (Fl_Callback *) History_cb_Undo, 0, 0, 0, 0, 14, 56},
3795     {gettext("Redo"), 0,  (Fl_Callback *) History_cb_Redo, 0, 0, 0, 0, 14, 56},
3796     {0},
3797     {0}
3798   };
3799 
autosave_rm()3800   void History_Fold::autosave_rm(){
3801     if (is_file_available(autosave_filename.c_str())){
3802       cerr << "Autosave remove " << autosave_filename << '\n';
3803       unlink(autosave_filename.c_str());
3804     }
3805   }
3806 
History_cb_fold_button(Fl_Button * b,void *)3807   void History_cb_fold_button(Fl_Button* b , void*){
3808     if (!b) return;
3809     History_Fold * hf = dynamic_cast<History_Fold *>(b->parent());
3810     if (hf){
3811       if (hf->_folded)
3812 	hf->unfold();
3813       else
3814 	hf->fold();
3815     }
3816   }
3817 
History_cb_current_status(Fl_Button * b,void *)3818   void History_cb_current_status(Fl_Button* b , void*){
3819     const giac::context * contextptr = get_context(b);
3820     Xcas_load_cas_setup(contextptr);
3821   }
3822 
History_cb_keyboard_button(Fl_Button * b,void *)3823   void History_cb_keyboard_button(Fl_Button* b , void*){
3824     if (Keyboard_Switch)
3825       Keyboard_Switch(1);
3826   }
3827 
History_cb_cmds_button(Fl_Button * b,void *)3828   void History_cb_cmds_button(Fl_Button* b , void*){
3829     if (Keyboard_Switch)
3830       Keyboard_Switch(4);
3831   }
3832 
History_cb_msg_button(Fl_Button * b,void *)3833   void History_cb_msg_button(Fl_Button* b , void*){
3834     if (Keyboard_Switch)
3835       Keyboard_Switch(2);
3836   }
3837 
History_cb_save_button(Fl_Button * b,void *)3838   void History_cb_save_button(Fl_Button* b , void*){
3839     if (!b) return;
3840     History_Fold * hf = get_history_fold(b);
3841     if (hf){
3842       hf->pack->save();
3843       hf->redraw();
3844     }
3845   }
3846 
History_cb_help_index(Fl_Widget * wid,void *)3847   void History_cb_help_index(Fl_Widget * wid,void *){
3848     static std::string ans;
3849     if (!wid)
3850       return;
3851     int remove,ii;
3852     Fl_Widget * w=xcas::Xcas_input_focus;
3853     Fl_Window * wd=wid->window();
3854     if (
3855 	(ii=xcas::handle_tab("",(*giac::vector_completions_ptr()),wd->w()/3,wd->h()/3,remove,ans)) ){
3856       if (ii==1)
3857 	ans = ans +"()";
3858       Fl::e_text = (char * ) ans.c_str();
3859       Fl::e_length = ans.size();
3860       if (w){
3861 	xcas::fl_handle(w);
3862 	if (Fl_Input * in =dynamic_cast<Fl_Input *>(w)){
3863 	  if (ii==1) in->position(in->position()-1);
3864 	}
3865       }
3866     }
3867   }
3868 
History_cb_tex_button(Fl_Widget * b,void *)3869   void History_cb_tex_button(Fl_Widget* b , void*){
3870     static std::string s;
3871     giac::gen g;
3872     const context * contextptr=get_context(b);
3873     try {
3874       if (xcas::Equation * ptr=dynamic_cast<xcas::Equation *> (Fl::focus()))
3875 	g=ptr->get_selection();
3876       if (xcas::Flv_Table_Gen * ptr=dynamic_cast<xcas::Flv_Table_Gen *> (Fl::focus()))
3877 	g=extractmatricefromsheet(ptr->selected);
3878       if (Fl_Input_ * ptr=dynamic_cast<Fl_Input *>(Fl::focus())){
3879 	int i=ptr->position(),j=ptr->mark();
3880 	if (i>j) swapint(i,j);
3881 	s=ptr->value();
3882 	s=s.substr(i,j-i);
3883 	g=giac::gen(s,contextptr);
3884       }
3885       s=giac::gen2tex(g,0);
3886     }
3887     catch (std::runtime_error & e){
3888       s = e.what()+g.print(contextptr);
3889     }
3890     int ss=s.size();
3891     Fl::copy(s.c_str(),ss,0);
3892     Fl::copy(s.c_str(),ss,1);
3893   }
3894 
History_cb_help_button(Fl_Widget * b,void *)3895   void History_cb_help_button(Fl_Widget* b , void*){
3896     static char petit_buffer[]={9,0};
3897     xcas::Xcas_Text_Editor * ed=dynamic_cast<xcas::Xcas_Text_Editor *>(Fl::focus());
3898     if (ed){
3899       ed->completion();
3900       return;
3901     }
3902     xcas::Multiline_Input_tab * in=dynamic_cast<xcas::Multiline_Input_tab *>(Fl::focus());
3903     if (in){
3904       Fl::e_length=1;
3905       Fl::e_text=petit_buffer;
3906       xcas::fl_handle(Fl::focus());
3907     }
3908     else
3909       History_cb_help_index(b,0);
3910   }
3911 
History_cb_stop_button(Fl_Widget * b,void *)3912   void History_cb_stop_button(Fl_Widget* b , void*){
3913 #ifndef __APPLE__
3914     if (xcas::interrupt_button){
3915       xcas::interrupt_button=false;
3916       xcas::History_Pack * hp =xcas::get_history_fold(b)->pack;
3917       context * cptr=hp?hp->contextptr:0;
3918       cerr << gettext("STOP pressed. Trying to cancel cleanly") << '\n';
3919       if (!Fl::event_state(FL_SHIFT)){
3920 	giac::ctrl_c=true;
3921 	for (int j=0;j<300;j++){
3922 	  if (!giac::ctrl_c){
3923 	    *logptr(cptr) << gettext("Cleanly cancelled.") << '\n';
3924 	    giac::interrupted=false;
3925 	    xcas::interrupt_button=true;
3926 	    return;
3927 	  }
3928 	  usleep(10000);
3929 	}
3930 	giac::ctrl_c=false;  giac::interrupted=false;
3931       }
3932       *logptr(cptr) << gettext("Cancelling thread. Xcas may crash now or later :-( Consider saving and restarting Xcas.") << '\n';
3933       xcas::interrupt_button=true;
3934       if (giac::is_context_busy(hp?hp->contextptr:0)){
3935         giac::kill_thread(true,hp?hp->contextptr:0);
3936         return;
3937       }
3938     }
3939 #else
3940     static Fl_Window * w = 0;
3941     static Fl_Button * button = 0;
3942     static string s("10");
3943     if (xcas::interrupt_button){
3944       xcas::interrupt_button=false;
3945       xcas::History_Pack * hp =xcas::get_history_fold(b)->pack;
3946       context * cptr=hp?hp->contextptr:0;
3947       *logptr(cptr) << gettext("STOP pressed. Trying to cancel cleanly") << '\n';
3948       if (!w){
3949 	Fl_Group::current(0);
3950 	w=new Fl_Window(200,50);
3951 	button = new Fl_Button(2,2,w->w()-4,w->h()-4);
3952 	w->label(gettext("Cancelling"));
3953 	w->end();
3954       }
3955       w->set_modal();
3956       w->show();
3957       w->hotspot(w);
3958       Fl::focus(w);
3959       Fl::flush();
3960       if (!Fl::event_state(FL_SHIFT)){
3961 	giac::ctrl_c=true;
3962 	for (int k=5;k>=0;--k){
3963 	  s=gettext("Trying to cancel cleanly: ")+print_INT_(k);
3964 	  button->label(s.c_str());
3965 	  Fl::flush();
3966 #ifdef HAVE_LIBPTHREAD
3967 	  Fl::unlock();
3968 #endif
3969 	  for (int j=0;j<100;j++){
3970 	    if (!giac::ctrl_c){
3971 	       giac::interrupted=false;
3972 	      w->hide();
3973 	      *logptr(cptr) << gettext("Cleanly cancelled.") << '\n';
3974 	      xcas::interrupt_button=true;
3975 	      return;
3976 	    }
3977 	    usleep(10000);
3978 	  }
3979 	}
3980 	giac::ctrl_c=false; giac::interrupted=false;
3981       }
3982       w->hide();
3983       xcas::interrupt_button=true;
3984       if (giac::is_context_busy(hp?hp->contextptr:0)){
3985 	*logptr(cptr) << gettext("Cancelling thread. Xcas may crash now or later :-( Consider saving and restarting Xcas.") << '\n';
3986         giac::kill_thread(true,hp?hp->contextptr:0);
3987         return;
3988       }
3989     }
3990 #endif
3991   }
3992 
update_status()3993   void History_Fold::update_status(){
3994     const giac::context * ptr = pack->contextptr;
3995     if (is_context_busy(ptr))
3996       stop_button->activate();
3997     else {
3998       ++update_status_count;
3999       if (!stop_button->active() &&
4000 #ifdef WIN32
4001 	  (update_status_count%64)
4002 #else
4003 	  (update_status_count%64)
4004 #endif
4005 	  )
4006 	return;
4007       stop_button->deactivate();
4008     }
4009     if (current_status){
4010       string mode_s="Config ";
4011       if (pack->url)
4012 	mode_s += '\''+remove_path(*pack->url)+'\'';
4013       mode_s += " :";
4014 #ifdef IPAQ
4015       if (giac::approx_mode(ptr))
4016 	mode_s += " ~ ";
4017       else
4018 	mode_s += " = ";
4019 #else
4020       if (giac::approx_mode(ptr))
4021 	mode_s += " approx ";
4022       else
4023 	mode_s += " exact ";
4024 #endif
4025       if (giac::complex_mode(ptr)){
4026 	if (giac::complex_variables(ptr))
4027 	  mode_s += "CPLX ";
4028 	else
4029 	  mode_s += "cplx ";
4030       }
4031       else
4032 	mode_s += "real ";
4033       if (giac::angle_radian(ptr))
4034 	mode_s+="RAD ";
4035       else
4036 	mode_s+="DEG ";
4037       mode_s += giac::print_INT_(giac::decimal_digits(ptr));
4038       mode_s += ' ';
4039       switch (giac::xcas_mode(ptr)){
4040       case 0:
4041 	if (python_compat(ptr))
4042 	  mode_s += python_compat(ptr)==2?"python ^==xor ":"python ^=** ";
4043 	else
4044 	  mode_s+="xcas ";
4045 	break;
4046       case 1:
4047 	mode_s+="maple "; break;
4048       case 2:
4049 	mode_s+="mupad "; break;
4050       case 3:
4051 	mode_s+="ti89 "; break;
4052       }
4053       /*
4054 	if (giac::withsqrt(0))
4055 	mode_s += "sqrt ";
4056 	else
4057 	mode_s += "Q[X] ";
4058       */
4059       // mode_s += "Time: ";
4060       // double t=double(clock());
4061       // mode_s += xcas::print_DOUBLE_(t/CLOCKS_PER_SEC);
4062 #ifdef HAVE_MALLOC_H //
4063       struct mallinfo mem=mallinfo();
4064       double memd=mem.arena+mem.hblkhd;
4065       mode_s +=xcas::print_DOUBLE_(memd/1048576);
4066       mode_s += "M ";
4067 #endif //
4068       /*
4069 	char * ch = getcwd(0,0);
4070 	mode_s += ch;
4071 	free(ch);
4072       */
4073       mode_s += ' ';
4074       // mode_s += label();
4075       if (!current_status->label() || mode_s!= current_status->label()){
4076 	if (mode)
4077 	  delete [] mode;
4078 	mode = new char[mode_s.size()+1];
4079 	strcpy(mode,mode_s.c_str());
4080 	current_status->label(mode);
4081       }
4082     }
4083   }
4084 
History_Fold(int X,int Y,int W,int H,int showmenu,const char * l)4085   History_Fold::History_Fold(int X,int Y,int W,int H,int showmenu,const char*l):Fl_Group(X,Y,W,H,l),_folded(false),mode(0) {
4086     end();
4087     update_status_count=-1;
4088     if (!l)
4089       label(gettext("Unnamed"));
4090     if (parent()){
4091       labelsize(parent()->labelsize());
4092       labelfont(parent()->labelfont());
4093     }
4094     int L=labelsize()+labeladd;
4095     scroll_position=-1;
4096     // Fl_Group::current(this);
4097     // box(FL_FLAT_BOX);
4098     _bordersize=labelsize();
4099     autosave_filename = autosave_folder+"xcas_auto_";
4100     size_t ul=(size_t) this;
4101     autosave_filename += print_INT_(ul);
4102     autosave_filename += ".xws";
4103     scroll = new Fl_Scroll(X,Y+L,W,H-L);
4104     scroll->end();
4105     scroll->box(FL_FLAT_BOX);
4106     pack=new History_Pack(scroll->x(),scroll->y(),max(W-labelsize(),_bordersize),H-2*L);
4107     pack->end();
4108     scroll->add(pack);
4109     scroll->resizable(pack);
4110     Fl_Group::add(scroll);
4111     Fl_Group::resizable(scroll);
4112     bnd_button=0;
4113     group=0;
4114     save_button=0;
4115     current_status=0;
4116     stop_button=0;
4117     keyboard_button=0;
4118     msg_button=0;
4119     close_button=0;
4120     mb=0;
4121     fold_button=0;
4122     input=0;
4123     if (showmenu){
4124       group = new Fl_Group(X,Y+2,W,L-2);
4125       help_button = new No_Focus_Button(X,Y+1,L,L-2,"?");
4126       help_button->callback((Fl_Callback*) History_cb_help_button);
4127       help_button->tooltip(gettext("Online help and command completion"));
4128       help_button->color(FL_CYAN);
4129       save_button = new Fl_Button(X+L,Y+1,3*L,L-2,gettext("Save"));
4130       save_button->color(Xcas_save_saved_color);
4131       save_button->callback((Fl_Callback*) History_cb_save_button);
4132       save_button->tooltip(gettext("Save current session"));
4133       save_button->align(Fl_Align(68|FL_ALIGN_INSIDE));
4134 #ifdef IPAQ
4135       bnd_button = new No_Focus_Button(X+8*L,Y+1,2*L,L-2,"bnd");
4136       bnd_button->callback((Fl_Callback*) History_cb_tex_button);
4137       bnd_button->tooltip(gettext("Switch bandeau on or off"));
4138       current_status = new Fl_Button(X+6*L,Y+1,max(W-14*L,0),L-2);
4139       current_status->align(FL_ALIGN_LEFT|FL_ALIGN_CLIP |FL_ALIGN_INSIDE);
4140 #else
4141       current_status = new Fl_Button(X+4*L,Y+1,max(W-12*L,0),L-2);
4142       current_status->align(FL_ALIGN_CENTER|FL_ALIGN_CLIP |FL_ALIGN_INSIDE);
4143 #endif
4144       current_status->label("");
4145       current_status->labelfont(FL_HELVETICA_ITALIC);
4146       current_status->callback((Fl_Callback*) History_cb_current_status);
4147       current_status->tooltip(gettext("Current CAS status. Click to modify"));
4148       stop_button = new No_Focus_Button(current_status->x()+current_status->w(),current_status->y(),3*L,L-2);
4149       stop_button->label("STOP");
4150       stop_button->callback((Fl_Callback*) History_cb_stop_button);
4151       stop_button->labelcolor(FL_RED);
4152       stop_button->tooltip(gettext("Interrupt current computation"));
4153       stop_button->deactivate();
4154       xcas::Xcas_Cancel=stop_button; // FIXME when history fold destroyed
4155       keyboard_button = new No_Focus_Button(stop_button->x()+stop_button->w(),Y+1,3*L,L-2,gettext("Kbd"));
4156       keyboard_button->callback((Fl_Callback*) History_cb_keyboard_button);
4157       keyboard_button->tooltip(gettext("Switch keyboard on or off"));
4158       // msg_button = new No_Focus_Button(keyboard_button->x()+keyboard_button->w(),Y+1,2*L,L-2,"Msg");
4159       // msg_button->callback((Fl_Callback*) History_cb_msg_button);
4160       // msg_button->tooltip("Show messages line");
4161       // close_button = new Fl_Button(msg_button->x()+msg_button->w(),stop_button->y(),L,L-2);
4162       close_button = new Fl_Button(keyboard_button->x()+keyboard_button->w()+L,stop_button->y(),L,L-2);
4163       close_button->label("X");
4164       close_button->callback((Fl_Callback*) hf_Kill);
4165       close_button->tooltip(gettext("Close current session"));
4166       group->end();
4167       group->resizable(current_status);
4168       Fl_Group::add(group);
4169       /*
4170       mb = new Fl_Menu_Button(X,Y,W,L);
4171       mb->type(Fl_Menu_Button::POPUP3);
4172       mb->box(FL_NO_BOX);
4173       mb->menu(History_menu);
4174       Fl_Group::add(mb);
4175       */
4176     }
4177     else {
4178       labeltype(FL_NO_LABEL);
4179       fold_button = new Fl_Button(X,Y+1,L,L-2,"-");
4180       fold_button->color(Xcas_save_saved_color);
4181       fold_button->callback((Fl_Callback*) History_cb_fold_button);
4182       Fl_Group::add(fold_button);
4183       // only one of input or group will be visible
4184       input = new Fl_Input(X+L,Y+1,W-L,L-2);
4185       input->textfont(FL_HELVETICA_BOLD_ITALIC);
4186       // input->label("");
4187       Fl_Group::add(input);
4188     }
4189     change_group_fontsize(this,labelsize());
4190     set_colors(this);
4191     parent_redraw(this);
4192   }
4193 
add_entry(int n)4194   bool History_Fold::add_entry(int n){
4195     if (!pack->new_question )
4196       return false;
4197     int edw=max(w()-pack->_printlevel_w,_bordersize);
4198     int edh=editor_hsize(this);
4199     Fl_Widget * q=pack->new_question(edw,edh);
4200     q->resize(pack->x(),pack->y(),q->w(),q->h());
4201     pack->add_entry(n,q);
4202     return true;
4203   }
4204 
add_entry(int n,Fl_Widget * q)4205   void History_Fold::add_entry(int n,Fl_Widget * q){
4206     pack->add_entry(n,q);
4207   }
4208 
add_history_map(Fl_Widget * g,int undo_position)4209   void History_Pack::add_history_map(Fl_Widget * g,int undo_position){
4210     std::multimap<Fl_Widget *,indexed_string>::iterator it0=widget_history_map.lower_bound(g),it=it0,itend=widget_history_map.upper_bound(g);
4211     for (;it!=itend;++it){
4212       if (it->second.index>undo_position)
4213 	break;
4214     }
4215     if (it==it0)
4216       widget_history_map.insert(it0,pair<Fl_Widget *,indexed_string>(g,indexed_string(undo_position,"")));
4217     else {
4218       --it;
4219       if (it->second.chaine.empty())
4220 	it->second.chaine=widget_sprint(g);
4221       else
4222       widget_history_map.insert(it,pair<Fl_Widget *,indexed_string>(g,indexed_string(undo_position,"")));
4223     }
4224   }
4225 
restore_history_map(Fl_Widget * g,int undo_position)4226   Fl_Widget * History_Pack::restore_history_map(Fl_Widget * g,int undo_position){
4227     std::multimap<Fl_Widget *,indexed_string>::const_iterator it0=widget_history_map.lower_bound(g),it=it0,itend=widget_history_map.upper_bound(g);
4228     if (it==itend)
4229       return 0;
4230     for (;it!=itend;++it){
4231       if (it->second.index>undo_position)
4232 	break;
4233     }
4234     if (it==it0)
4235       return 0;
4236     --it;
4237     if (it->second.chaine.empty())
4238       return it->first; // widget pointer points to an actual widget
4239     // restore widget from string representation
4240     string s=it->second.chaine;
4241     int ss=s.size(),pos=0;
4242     Fl_Group::current(0);
4243     Fl_Widget * res=widget_load(s,ss,pos,contextptr);
4244     add_history_map(res,undo_position);
4245     return res;
4246   }
4247 
remove_entry(int n,bool check)4248   bool History_Pack::remove_entry(int n,bool check){
4249     if (check && is_context_busy(contextptr)){
4250       fl_message("%s",gettext("Unable to cut. Xcas is busy."));
4251       return false;
4252     }
4253     int m=children();
4254     if (n>=m)
4255       return false;
4256     Fl_Widget * g= child(n);
4257     int pos;
4258     if (get_history_pack(Xcas_input_focus,pos) && pos==n)
4259       Xcas_input_focus=0;
4260     add_history_map(g,undo_position);
4261     remove(g);
4262     delete g;
4263     modified(false);
4264     parent_redraw(this);
4265     return true;
4266   }
4267 
4268   // Note: all calls are done with check=false
4269   // If true they don't work inside an icas session geo2d("");
4270   // I don't remember why check_in_history_fold was introduced...
remove_selected_levels(bool check_in_history_fold)4271   bool History_Pack::remove_selected_levels(bool check_in_history_fold){
4272     if (check_in_history_fold){
4273       if (!get_history_fold(this))
4274 	return false;
4275     }
4276     if (is_context_busy(contextptr)){
4277       fl_message("%s",gettext("Unable to cut. Xcas is busy."));
4278       return false;
4279     }
4280     int s1=_sel_begin, s2= _sel_end;
4281     if (s1<0 || s2<0){
4282       fl_alert("%s",gettext("First select level(s):\nclick on the level numbers near the left border"));
4283     }
4284     if (s1>=0 && s2>=0){
4285       int m=min(s1,s2),M=max(s1,s2);
4286       update_pos=m;
4287       for (int i=m;i<=M;++i)
4288 	remove_entry(m);
4289       _sel_end=_sel_begin=-1;
4290       backup();
4291       update();
4292       resize();
4293       return true;
4294     }
4295     return false;
4296   }
4297 
remove_entry(int n)4298   bool History_Fold::remove_entry(int n){
4299     return pack->remove_entry(n);
4300   }
4301 
handle(int event)4302   int History_Fold::handle(int event){
4303     // if (Fl::event_button()== FL_RIGHT_MOUSE)
4304     //  return 0;
4305     return Fl_Group::handle(event);
4306   }
4307 
resize(int X,int Y,int W,int H)4308   void History_Fold::resize(int X,int Y,int W,int H){
4309     scroll_position = scroll->yposition();
4310     Fl_Widget::resize(X,Y,W,H);
4311     int L=labelsize()+labeladd;
4312     if (L>H)
4313       L=H;
4314     if (mb) mb->resize(X,Y,W,L); // (X,Y,W,H) not compatible w/ geo right-click
4315     if (fold_button) fold_button->resize(X,Y+2,L,L-2);
4316     if (input) input->resize(X+L,Y+2,W-L,L-2);
4317     if (group) group->resize(X,Y+2,W,L-2);
4318     // save_button->resize(X+3*L,Y+2,3*L,L-2);
4319     scroll->resize(X,Y+L,W,H-L);
4320     int sw=min(max(labelsize(),10),16);
4321     Fl_Scrollbar & ss = scroll->scrollbar;
4322     ss.resize(W-sw,ss.y(),sw,ss.h());
4323     // FIXME should use the vertical scrollbar size instead of bordersize
4324     pack->Fl_Widget::resize(pack->x(),pack->y(),max(W-sw-L,_bordersize),pack->h());
4325     pack->resize();
4326   }
4327 
parent_redraw(Fl_Widget * w)4328   void parent_redraw(Fl_Widget * w){
4329     if (w->parent())
4330       w->parent()->redraw();
4331     else
4332       w->redraw();
4333   }
4334 
parents_redraw(Fl_Widget * w)4335   void parents_redraw(Fl_Widget * w){
4336     if (w->parent())
4337       parents_redraw(w->parent());
4338     w->damage(FL_DAMAGE_ALL);
4339     w->redraw();
4340   }
4341 
brothers_redraw(Fl_Widget * w)4342   void brothers_redraw(Fl_Widget * w){
4343     if (!w->parent())
4344       return;
4345     Fl_Group * gr = w->parent();
4346     int n=gr->children();
4347     for (int i=0;i<n;++i){
4348       gr->child(i)->redraw();
4349     }
4350     gr->redraw();
4351   }
4352 
resize_parent(int H)4353   void History_Fold::resize_parent(int H){
4354     Fl_Group * g=parent();
4355     if (g && g->children()==1){
4356       if (_folded)
4357 	_hsorig=g->h();
4358       g->Fl_Widget::resize(g->x(),g->y(),g->w(),H);
4359     }
4360   }
4361 
fold()4362   void History_Fold::fold(){
4363     if (!mb && !_folded){
4364       _folded=true;
4365       if (fold_button){
4366 	fold_button->label("+");
4367 	fold_button->redraw();
4368       }
4369       _horig=h();
4370       scroll->hide();
4371       int L=labelsize()+labeladd;
4372       resize(x(),y(),w(),L);
4373       resize_parent(2*L);
4374       if (window()) window()->redraw();
4375     }
4376   }
4377 
unfold()4378   void History_Fold::unfold(){
4379     if (!mb && _folded){
4380       _folded=false;
4381       if (fold_button){
4382 	fold_button->label("-");
4383 	fold_button->redraw();
4384       }
4385       scroll->show();
4386       resize_parent(_hsorig);
4387       resize(x(),y(),w(),_horig);
4388       Fl::flush();
4389       brothers_redraw(parent());
4390       if (pack->children())
4391 	pack->focus(0);
4392     }
4393   }
4394 
draw()4395   void History_Fold::draw(){
4396     int clip_x,clip_y,clip_w,clip_h;
4397     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
4398     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
4399     /*
4400     if (scroll_position>0){
4401       Fl_Group::draw();
4402       scroll->position(0,scroll_position);
4403       scroll_position=-1;
4404       Fl_Group::draw();
4405     }
4406     else
4407     */
4408       Fl_Group::draw();
4409     fl_pop_clip();
4410   }
4411 
4412 
draw()4413   void HScroll::draw(){
4414 #ifdef __APPLE__
4415     redraw();
4416 #endif
4417     Fl_Scroll::draw();
4418   }
4419 
group_resize(Fl_Group * gr)4420   void group_resize(Fl_Group * gr){
4421     int n=gr->children();
4422     if (n!=3)
4423       return;
4424     History_Pack * Main_Pack = dynamic_cast<History_Pack *>(gr->child(0));
4425     if (Main_Pack){
4426       int ch=Main_Pack->children();
4427       if (ch){
4428 	int widy=Main_Pack->child(0)->y();
4429 	int widx=Main_Pack->child(0)->x();
4430 	int widw=gr->w()-6-gr->labelsize();
4431 	int space=Main_Pack->_spacing;
4432 	int widh=(gr->h()-10-(ch-1)*space)/ch;
4433 	for (int i=0;i<ch;i++){
4434 	  Fl_Widget * wid =Main_Pack->child(i);
4435 	  wid->resize(widx,widy,widw,widh);
4436 	  widy += widh+space;
4437 	}
4438       }
4439       Main_Pack->Fl_Widget::resize(gr->x()+2,gr->y()+2,gr->w()-6,gr->h()-10);
4440       gr->Fl_Group::resize(gr->x(),gr->y(),gr->w(),gr->h());
4441     }
4442   }
4443 
resize()4444   void HScroll::resize(){
4445     group_resize(this);
4446   }
4447 
resize(int X,int Y,int W,int H)4448   void HScroll::resize(int X,int Y,int W,int H){
4449     Fl_Scroll::resize(X,Y,W,H);
4450     int L=labelsize();
4451     L=L>14?14:L;
4452     L=L<8?8:L;
4453     scrollbar.resize(scrollbar.x()+scrollbar.w()-L,scrollbar.y(),L,scrollbar.h());
4454     if (resizechildren)
4455       resize();
4456     else {
4457       // resize children horizontally
4458       int W1 = max(W -L-6,labelsize());
4459       Fl_Widget ** a=(Fl_Widget **) array();
4460       int n=children();
4461       int H1=0;
4462       for (int i=2;i<n;++i,++a){
4463 	H1 += (*a)->h();
4464       }
4465       if (H1<H)
4466 	W1=W-6;
4467       a=(Fl_Widget **) array();
4468       for (int i=2;i<n;++i,++a){
4469 	Fl_Widget * o = *a;
4470 	o->resize(X+2,o->y(),W1,o->h());
4471       }
4472     }
4473     redraw(); // since children have been modified
4474   }
4475 
draw()4476   void DispG_Window::draw(){
4477     //COUT << "DispG draw" << '\n';
4478     Fl_Window::draw();
4479   }
4480 
handle(int event)4481   int DispG_Window::handle(int event){
4482     int res=Fl_Window::handle(event);
4483     if (event==FL_HIDE){
4484       int n=children();
4485       for (int i=0;i<n;++i){
4486 	Fl_Group * t = dynamic_cast<Fl_Group *>(child(i));
4487 	if (t && t->children()){
4488 	  Graph2d3d * gr=dynamic_cast<Graph2d3d *>(t->child(0));
4489 	  // if (gr) gr->clear(); // commented otherwise iconize clears graph
4490 	}
4491       }
4492     }
4493     return res;
4494   }
4495 
4496   // Implementation of widget output stream
4497 #ifdef WITH_MYOSTREAM
owstream(Fl_Output * wid,context * ptr,int bsize)4498   owstream::owstream(Fl_Output * wid,context * ptr, int bsize):my_ostream(new widgetbuf(wid, bsize)),output(wid),contextptr(ptr) {}
4499 
~owstream()4500   owstream::~owstream(){
4501     ostream * ptr=logptr(contextptr);
4502     if (ptr==this)
4503       logptr(&my_cerr,contextptr);
4504     //if (tie())      delete tie();
4505   }
4506 #else
owstream(Fl_Output * wid,context * ptr,int bsize)4507   owstream::owstream(Fl_Output * wid,context * ptr, int bsize):ostream(new widgetbuf(wid, bsize)),output(wid),contextptr(ptr) {}
4508 
~owstream()4509   owstream::~owstream(){
4510     ostream * ptr=logptr(contextptr);
4511     if (ptr==this)
4512       logptr(&std::cerr,contextptr);
4513     //if (tie())      delete tie();
4514   }
4515 #endif
4516 
output_resize(Fl_Input_ * output)4517   void output_resize(Fl_Input_ * output){
4518     if (!output)
4519       return;
4520     Fl_Widget * ptr = output->window();
4521     int maxh = ptr?(ptr->h()/3):400;
4522     const char * ch=output->value();
4523     int n=strlen(ch);
4524     int h0=output->labelsize()+4,res=n?h0+2:1;
4525     for (int i=0;i<n-1;++i,++ch){
4526       if (*ch=='\n'){
4527 	res += h0;
4528 	if (res>maxh)
4529 	  break;
4530       }
4531     }
4532     output->resize(output->x(),output->y(),output->w(),res);
4533     if (n){
4534       output->position(n-1,n-1);
4535     }
4536   }
4537 
output_resize_parent(Fl_Input_ * output,bool resize_hp)4538   void output_resize_parent(Fl_Input_ * output,bool resize_hp){
4539     int dhlog = -output->h();
4540     output_resize(output);
4541     dhlog += output->h();
4542     Fl_Group * gr = output->parent();
4543     if (gr){
4544       int m=gr->children();
4545       gr->Fl_Widget::resize(gr->x(),gr->y(),gr->w(),gr->h()+dhlog);
4546       for (int i=0;i<m;i++){
4547 	Fl_Widget * tmp=gr->child(i);
4548 	if (tmp->y()>output->y())
4549 	  tmp->resize(tmp->x(),tmp->y()+dhlog,tmp->w(),tmp->h());
4550       }
4551     }
4552     if (resize_hp){
4553       if (History_Pack * hp=get_history_pack(gr)){
4554 	hp->resize();
4555 	if (Fl_Scroll * s = dynamic_cast<Fl_Scroll *>(hp->parent())){
4556 	  int spos=s->yposition();
4557 	  if (spos+s->h()>hp->h()){
4558 #ifdef _HAVE_FL_UTF8_HDR_
4559 	    s->scroll_to(0,max(min(hp->h()-s->h(),spos+dhlog),0));
4560 #else
4561 	    s->position(0,max(min(hp->h()-s->h(),spos+dhlog),0));
4562 #endif
4563 	  }
4564 	  s->redraw();
4565 	}
4566       }
4567     }
4568   }
4569 
4570   // resize log widget stream
resize()4571   void owstream::resize(){
4572     output_resize(output);
4573   }
4574 
widgetbuf(Fl_Output * wid,int bsize)4575   widgetbuf::widgetbuf(Fl_Output * wid, int bsize): streambuf(),text(wid){
4576     if (bsize)
4577       {
4578 	char	*ptr = new char[bsize];
4579 	setp(ptr, ptr + bsize);
4580       }
4581     else
4582       setp(0, 0);
4583 
4584     setg(0, 0, 0);
4585   }
4586 
~widgetbuf()4587   widgetbuf::~widgetbuf(){
4588     sync();
4589     delete[] pbase();
4590   }
4591 
overflow(int c)4592   int widgetbuf::overflow(int c){
4593     put_buffer();
4594     if (c != EOF){
4595       if (pbase() == epptr())
4596 	put_char(c);
4597       else
4598 	sputc(c);
4599     }
4600     return 0;
4601   }
4602 
sync()4603   int	widgetbuf::sync()
4604   {
4605     put_buffer();
4606     return 0;
4607   }
4608 
put_char(int chr)4609   void	widgetbuf::put_char(int chr)
4610   {
4611     char ch[2];
4612     ch[0]=chr;
4613     ch[1]=0;
4614 #ifdef HAVE_LIBPTHREAD
4615     Fl::lock();
4616 #endif
4617     if (chr=='')
4618       text->value("");
4619     else {
4620       int n=strlen(text->value());
4621       text->position(n,n);
4622       text->insert(ch);
4623     }
4624 #ifdef HAVE_LIBPTHREAD
4625     Fl::unlock();
4626 #endif
4627     if (chr=='\n'){
4628       int n=text->position();
4629       if (n)
4630 	text->position(n-1,n-1);
4631       Fl::awake(text);
4632     }
4633   }
4634 
put_buffer()4635   void	widgetbuf::put_buffer()
4636   {
4637     if (pbase() != pptr())
4638       {
4639 	int     len = (pptr() - pbase());
4640 	char    *buffer = new char[len + 1];
4641 
4642         strncpy(buffer, pbase(), len);
4643 	buffer[len] = 0;
4644 #ifdef HAVE_LIBPTHREAD
4645 	Fl::lock();
4646 #endif
4647 	text->insert(buffer);
4648 #ifdef HAVE_LIBPTHREAD
4649 	Fl::unlock();
4650 #endif
4651 	Fl::awake(text);
4652 
4653         setp(pbase(), epptr());
4654 	delete [] buffer;
4655       }
4656   }
4657 
draw()4658   void Clip_Scroll::draw(){
4659     int clip_x,clip_y,clip_w,clip_h;
4660     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
4661     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
4662     // cerr << this << " " << x() << " " << y() << " " << w() << " " << h() << " " << clip_x << " " << clip_y << " " << clip_w << " " << clip_h << " " << int(damage()) << '\n';
4663     Fl_Scroll::draw();
4664     fl_pop_clip();
4665   }
4666 
resize(int X,int Y,int W,int H)4667   void Xcas_Tabs::resize(int X,int Y,int W,int H){
4668     Fl_Tabs::resize(X,Y,W,H);
4669     int n=children();
4670     int L=labelsize()+4;
4671     X += 1;
4672     W -= 2;
4673     H -= L-1;
4674     if (up)
4675       Y +=L;
4676     for (int i=0;i<n;++i){
4677       child(i)->resize(X,Y,W,H);
4678     }
4679   }
4680 
handle(int event)4681   int Log_Output::handle(int event){
4682     if (event!=FL_MOUSEWHEEL)
4683       return Fl_Multiline_Output::handle(event);
4684     return 0; // FIXME
4685     if (!Fl::event_inside(this))
4686       return 0;
4687     int n=Fl::e_dy;
4688     int i=position(),iorig=i,s=size();
4689     if (!s)
4690       return 0;
4691     if (n>0){
4692       for (;n;--n){
4693 	for (++i;i<s-1;++i){
4694 	  if (value()[i]==10)
4695 	    break;
4696 	}
4697       }
4698     }
4699     else {
4700       for (;n;++n){
4701 	for (--i;i>0;--i){
4702 	  if (value()[i]==10)
4703 	    break;
4704 	}
4705       }
4706     }
4707     if (i==iorig)
4708       return 0;
4709     position(i,i);
4710     return 1;
4711   }
4712 
4713 #ifndef NO_NAMESPACE_XCAS
4714 } // namespace xcas
4715 #endif // ndef NO_NAMESPACE_XCAS
4716 
4717 #endif // HAVE_LIBFLTK
4718