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