1 // -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -g -c Equation.cc -DHAVE_CONFIG_H -DIN_GIAC -Wall" -*-
2 /*
3  *  Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #ifndef IN_GIAC
23 #include <giac/first.h>
24 #else
25 #include "first.h"
26 #endif
27 #include <string>
28 #ifdef HAVE_LIBFLTK
29 #include "Equation.h"
30 #include <FL/Fl.H>
31 #include <FL/fl_draw.H>
32 #include <FL/Fl_Window.H>
33 #include <FL/fl_ask.H>
34 #include <FL/Fl_File_Chooser.H>
35 #include <FL/Fl_Hold_Browser.H>
36 #include <FL/Fl_PNG_Image.H>
37 #include <FL/Fl_Return_Button.H>
38 #ifndef IN_GIAC
39 #include <giac/giac.h>
40 #else
41 #include "giac.h"
42 #include "graphtheory.h"
43 #endif
44 #include "History.h"
45 #include "Xcas1.h"
46 #include "Input.h"
47 #include "Equation.h"
48 #include "Graph.h"
49 #include <iostream>
50 #include <fstream>
51 using namespace std;
52 using namespace giac;
53 
54 #ifndef NO_NAMESPACE_XCAS
55 namespace xcas {
56 #endif // ndef NO_NAMESPACE_XCAS
57 
58   unsigned max_prettyprint_equation=5000;
59 
60 #ifdef _HAVE_FL_UTF8_HDR_
cst_greek_translate(string & s0)61   Fl_Font cst_greek_translate(string & s0){
62     string s1(s0);
63     s0="";
64     int n=s1.size();
65     for (int i=0;i<n;++i){
66       if (!isalpha(s1[i])){
67 	s0 += s1[i];
68 	continue;
69       }
70       string s;
71       for (;i<n;++i){
72 	if (!isalpha(s1[i])){
73 	  --i;
74 	  break;
75 	}
76 	s+=s1[i];
77       }
78       bool done=false;
79       switch (s.size()){
80       case 2:
81 	if (s=="mu"){
82 	  s0+="μ";
83 	  done=true;
84 	}
85 	if (s=="nu"){
86 	  s0+="ν";
87 	  done=true;
88 	}
89 	if (s=="pi"){
90 	  s0+="π";
91 	  done=true;
92 	}
93 	if (s=="xi"){
94 	  s0+="ξ";
95 	  done=true;
96 	}
97 	if (s=="Xi"){
98 	  s0+="Ξ";
99 	  done=true;
100 	}
101 	break;
102       case 3:
103 	if (s=="chi"){
104 	  s0+="χ";
105 	  done=true;
106 	}
107 	if (s=="phi"){
108 	  s0+="φ";
109 	  done=true;
110 	}
111 	if (s=="Phi"){
112 	  s0+="Φ";
113 	  done=true;
114 	}
115 	if (s=="eta"){
116 	  s0+="η";
117 	  done=true;
118 	}
119 	if (s=="rho"){
120 	  s0+="ρ";
121 	  done=true;
122 	}
123 	if (s=="tau"){
124 	  s0+="τ";
125 	  done=true;
126 	}
127 	if (s=="psi"){
128 	  s0+="ψ";
129 	  done=true;
130 	}
131 	if (s=="Psi"){
132 	  s0+="Ψ";
133 	  done=true;
134 	}
135 	break;
136       case 4:
137 	if (s=="beta"){
138 	  s0+="β";
139 	  done=true;
140 	}
141 	if (s=="Beta"){
142 	  s0+="β";
143 	  done=true;
144 	}
145 	if (s=="zeta"){
146 	  s0+="ζ";
147 	  done=true;
148 	}
149 	if (s=="Zeta"){
150 	  s0+="ζ";
151 	  done=true;
152 	}
153 	if (s=="alef"){
154 	  s0+="ℵ";
155 	  done=true;
156 	}
157 	break;
158       case 5:
159 	if (s=="alpha"){
160 	  s0+="α";
161 	  done=true;
162 	}
163 	if (s=="delta"){
164 	  s0+="δ";
165 	  done=true;
166 	}
167 	if (s=="Delta"){
168 	  s0+="Δ";
169 	  done=true;
170 	}
171 	if (s=="gamma"){
172 	  s0+="γ";
173 	  done=true;
174 	}
175 	if (s=="Gamma"){
176 	  s0+="Γ";
177 	  done=true;
178 	}
179 	if (s=="kappa"){
180 	  s0+="κ";
181 	  done=true;
182 	}
183 	if (s=="theta"){
184 	  s0+="θ";
185 	  done=true;
186 	}
187 	if (s=="Theta"){
188 	  s0+="Θ";
189 	  done=true;
190 	}
191 	if (s=="sigma"){
192 	  s0+="σ";
193 	  done=true;
194 	}
195 	if (s=="Sigma"){
196 	  s0+="Σ";
197 	  done=true;
198 	}
199 	if (s=="Omega"){
200 	  s0+="Ω";
201 	  done=true;
202 	}
203 	if (s=="omega"){
204 	  s0+="ω";
205 	  done=true;
206 	}
207 	break;
208       case 6:
209 	if (s=="lambda"){
210 	  s0+="λ";
211 	  done=true;
212 	}
213 	if (s=="Lambda"){
214 	  s0+="λ";
215 	  done=true;
216 	}
217 	break;
218       case 7:
219 	if (s=="epsilon"){
220 	  s0+="ε";
221 	  done=true;
222 	}
223 	if (s=="product"){
224 	  s0="Π";
225 	  done=true;
226 	}
227 	break;
228       case 8:
229 	if (s=="infinity"){
230 	  s0+="∞";
231 	  done=true;
232 	}
233 	break;
234       case 11:
235 	if (s=="euler_gamma"){
236 	  s0+="ϒ";
237 	  done=true;
238 	}
239 	break;
240       } // end switch
241       if (!done)
242 	s0+=s;
243     } // end for (int i=0;i<n;i++)
244     return FL_HELVETICA;
245   }
246 #else
247 
cst_greek_translate(string & s0)248   Fl_Font cst_greek_translate(string & s0){
249     int n=s0.size(),j;
250     for (j=n-1;j>=2;--j){
251       if (isalpha(s0[j]))
252 	break;
253     }
254     string s=s0.substr(0,j+1),sadd;
255     if (j<n-1)
256       sadd=s0.substr(j+1,n-1-j);
257     switch (s.size()){
258     case 2:
259     if (s=="mu"){
260       s0="m"+sadd;
261       return FL_SYMBOL;
262     }
263     if (s=="nu"){
264       s0="n"+sadd;
265       return FL_SYMBOL;
266     }
267     if (s=="pi"){
268       s0="p"+sadd;
269       return FL_SYMBOL;
270     }
271     if (s=="xi"){
272       s0="x"+sadd;
273       return FL_SYMBOL;
274     }
275     if (s=="Xi"){
276       s0="X"+sadd;
277       return FL_SYMBOL;
278     }
279     if (s=="im"){
280       s0="Á"+sadd;
281       return FL_SYMBOL;
282     }
283     if (s=="re"){
284       s0="Â"+sadd;
285       return FL_SYMBOL;
286     }
287     break;
288     case 3:
289     if (s=="chi"){
290       s0="c"+sadd;
291       return FL_SYMBOL;
292     }
293     if (s=="phi"){
294       s0="f"+sadd;
295       return FL_SYMBOL;
296     }
297     if (s=="Phi"){
298       s0="f"+sadd;
299       return FL_SYMBOL;
300     }
301     if (s=="eta"){
302       s0="h"+sadd;
303       return FL_SYMBOL;
304     }
305     if (s=="rho"){
306       s0="r"+sadd;
307       return FL_SYMBOL;
308     }
309     if (s=="tau"){
310       s0="t"+sadd;
311       return FL_SYMBOL;
312     }
313     if (s=="psi"){
314       s0="y"+sadd;
315       return FL_SYMBOL;
316     }
317     if (s=="Psi"){
318       s0="Y"+sadd;
319       return FL_SYMBOL;
320     }
321     break;
322     case 4:
323     if (s=="beta"){
324       s0="b"+sadd;
325       return FL_SYMBOL;
326     }
327     if (s=="Beta"){
328       s0="b"+sadd;
329       return FL_SYMBOL;
330     }
331     if (s=="zeta"){
332       s0="z"+sadd;
333       return FL_SYMBOL;
334     }
335     if (s=="Zeta"){
336       s0="z"+sadd;
337       return FL_SYMBOL;
338     }
339     break;
340     case 5:
341     if (s=="alpha"){
342       s0="a"+sadd;
343       return FL_SYMBOL;
344     }
345     if (s=="delta"){
346       s0="d"+sadd;
347       return FL_SYMBOL;
348     }
349     if (s=="Delta"){
350       s0="D"+sadd;
351       return FL_SYMBOL;
352     }
353     if (s=="gamma"){
354       s0="g"+sadd;
355       return FL_SYMBOL;
356     }
357     if (s=="Gamma"){
358       s0="G"+sadd;
359       return FL_SYMBOL;
360     }
361     if (s=="kappa"){
362       s0="k"+sadd;
363       return FL_SYMBOL;
364     }
365     if (s=="theta"){
366       s0="q"+sadd;
367       return FL_SYMBOL;
368     }
369     if (s=="Theta"){
370       s0="Q"+sadd;
371       return FL_SYMBOL;
372     }
373     if (s=="sigma"){
374       s0="s"+sadd;
375       return FL_SYMBOL;
376     }
377     if (s=="Sigma"){
378       s0="S"+sadd;
379       return FL_SYMBOL;
380     }
381     if (s=="Omega"){
382       s0="W"+sadd;
383       return FL_SYMBOL;
384     }
385     if (s=="omega"){
386       s0="w"+sadd;
387       return FL_SYMBOL;
388     }
389     if (s=="aleph"){
390       s0="À"+sadd;
391       return FL_SYMBOL;
392     }
393     break;
394     case 6:
395     if (s=="lambda"){
396       s0="l"+sadd;
397       return FL_SYMBOL;
398     }
399     if (s=="Lambda"){
400       s0="L"+sadd;
401       return FL_SYMBOL;
402     }
403     if (s=="approx"){
404       s0="»"+sadd;
405       return FL_SYMBOL;
406     }
407     break;
408     case 7:
409     if (s=="epsilon"){
410       s0="e"+sadd;
411       return FL_SYMBOL;
412     }
413     if (s=="product"){
414       s0="P"+sadd;
415       return FL_SYMBOL;
416     }
417     break;
418     case 8:
419     if (s=="infinity"){
420       s0="¥"+sadd;
421       return FL_SYMBOL;
422     }
423     break;
424     case 11:
425     if (s=="euler_gamma"){
426       s0="g"+sadd;
427       return FL_SYMBOL;
428     }
429     break;
430     }
431     return FL_HELVETICA;
432   }
433 #endif
434 
Equation_binary_search_pos(const eqwdata & e,int x,int y)435   int Equation_binary_search_pos(const eqwdata & e,int x,int y){
436     int ss=e.g._STRNGptr->size();
437     int debut=0,fin=ss,pos,l=0;
438     fl_font(FL_HELVETICA,e.eqw_attributs.fontsize);
439     for (;debut+1<fin;){
440       pos=(debut+fin)/2;
441       l=int(fl_width(e.g._STRNGptr->substr(0,pos).c_str()));
442       if (e.x+l<x)
443 	debut=pos;
444       else
445 	fin=pos;
446     }
447     int l2=int(fl_width(e.g._STRNGptr->substr(0,fin).c_str()));
448     x=x-e.x;
449     if (x-l>l2-x)
450       return fin;
451     else
452       return debut;
453   }
454 
Equation_multistring_selection(const_iterateur & it,const_iterateur & itend,bool search_active)455   bool Equation_multistring_selection(const_iterateur & it,const_iterateur & itend,bool search_active){
456     for (;it!=itend;++it){ // find first selection
457       if (it->type==_EQW){
458 	if (search_active){
459 	  if (it->_EQWptr->active)
460 	    break;
461 	}
462 	else {
463 	  if (it->_EQWptr->selected)
464 	    break;
465 	}
466       }
467     }
468     if (it==itend)
469       return false; // nothing selected
470     const_iterateur it_end_sel=it+1;
471     for (;it_end_sel!=itend;++it_end_sel){ // find last selection
472       if (it_end_sel->type==_EQW){
473 	if (search_active){
474 	  if (!it_end_sel->_EQWptr->active)
475 	    break;
476 	}
477 	else {
478 	  if (!it_end_sel->_EQWptr->selected)
479 	    break;
480 	}
481       }
482     }
483     itend=it_end_sel-1;
484     return true;
485   }
486 
Equation_total_size(const gen & g)487   eqwdata Equation_total_size(const gen & g){
488     if (g.type==_EQW)
489       return *g._EQWptr;
490     if (g.type!=_VECT || g._VECTptr->empty())
491       return eqwdata(0,0,0,0,attributs(0,0,0),undef);
492     return Equation_total_size(g._VECTptr->back());
493   }
494 
495   // find smallest value of y and height
Equation_y_dy(const gen & g,int & y,int & dy)496   void Equation_y_dy(const gen & g,int & y,int & dy){
497     y=0; dy=0;
498     if (g.type==_EQW){
499       y=g._EQWptr->y;
500       dy=g._EQWptr->dy;
501     }
502     if (g.type==_VECT){
503       iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
504       for (;it!=itend;++it){
505 	int Y,dY;
506 	Equation_y_dy(*it,Y,dY);
507 	// Y, Y+dY and y,y+dy
508 	int ymax=giacmax(y+dy,Y+dY);
509 	if (Y<y)
510 	  y=Y;
511 	dy=ymax-y;
512       }
513     }
514   }
515 
Equation_translate(gen & g,int deltax,int deltay)516   void Equation_translate(gen & g,int deltax,int deltay){
517     if (g.type==_EQW){
518       g._EQWptr->x += deltax;
519       g._EQWptr->y += deltay;
520       g._EQWptr->baseline += deltay;
521       return ;
522     }
523     if (g.type!=_VECT)
524       setsizeerr();
525     vecteur & v=*g._VECTptr;
526     iterateur it=v.begin(),itend=v.end();
527     for (;it!=itend;++it)
528       Equation_translate(*it,deltax,deltay);
529   }
530 
Equation_change_attributs(const gen & g,const attributs & newa)531   gen Equation_change_attributs(const gen & g,const attributs & newa){
532     if (g.type==_EQW){
533       gen res(*g._EQWptr);
534       res._EQWptr->eqw_attributs = newa;
535       return res;
536     }
537     if (g.type!=_VECT)
538       setsizeerr();
539     vecteur v=*g._VECTptr;
540     iterateur it=v.begin(),itend=v.end();
541     for (;it!=itend;++it)
542       *it=Equation_change_attributs(*it,newa);
543     return gen(v,g.subtype);
544   }
545 
Equation_subsizes(const gen & arg,const attributs & a,int windowhsize,GIAC_CONTEXT)546   vecteur Equation_subsizes(const gen & arg,const attributs & a,int windowhsize,GIAC_CONTEXT){
547     vecteur v;
548     if ( (arg.type==_VECT) && ( (arg.subtype==_SEQ__VECT)
549 				// || (!ckmatrix(arg))
550 				) ){
551       const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end();
552       for (;it!=itend;++it)
553 	v.push_back(Equation_compute_size(*it,a,windowhsize,contextptr));
554     }
555     else {
556       v.push_back(Equation_compute_size(arg,a,windowhsize,contextptr));
557     }
558     return v;
559   }
560 
561   // vertical merge with same baseline
562   // for vertical merge of hp,yp at top (like ^) add fontsize to yp
563   // at bottom (like lower bound of int) substract fontsize from yp
Equation_vertical_adjust(int hp,int yp,int & h,int & y)564   void Equation_vertical_adjust(int hp,int yp,int & h,int & y){
565     int yf=min(y,yp);
566     h=max(y+h,yp+hp)-yf;
567     y=yf;
568   }
569 
570   // utility for gen embedded widget memory allocation
fltk_fl_widget_delete_function(void * ptr)571   void fltk_fl_widget_delete_function(void * ptr){
572     Fl_Widget * w=(Fl_Widget *) ptr;
573     /* not attached to any group
574     if (w->parent()){
575       Fl_Group * wg=dynamic_cast<Fl_Group *>(w->parent());
576       if (wg)
577 	wg->remove(w);
578     }
579     */
580     delete w;
581   }
582 
Equation_compute_symb_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT)583   gen Equation_compute_symb_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){
584     if (g.type!=_SYMB)
585       return Equation_compute_size(g,a,windowhsize,contextptr);
586     unary_function_ptr & u=g._SYMBptr->sommet;
587     gen arg=g._SYMBptr->feuille,rootof_value;
588     if (u==at_rootof && arg.type==_VECT && arg._VECTptr->size()==2 && arg._VECTptr->front().type==_VECT && has_rootof_value(arg._VECTptr->back(),rootof_value,contextptr)){
589       return Equation_compute_symb_size(horner_rootof(*arg._VECTptr->front()._VECTptr,rootof_value,contextptr),a,windowhsize,contextptr);
590     }
591     if (u==at_multistring){
592       gen tmp=_multistring(arg,contextptr);
593       tmp.subtype=1;
594       return Equation_compute_size(tmp,a,windowhsize,contextptr);
595     }
596     if (u==at_makevector){
597       vecteur v(1,arg);
598       if (arg.type==_VECT)
599 	v=*arg._VECTptr;
600       iterateur it=v.begin(),itend=v.end();
601       for (;it!=itend;++it){
602 	if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_makevector) )
603 	  *it=_makevector(it->_SYMBptr->feuille,contextptr);
604       }
605       return Equation_compute_size(v,a,windowhsize,contextptr);
606     }
607     if (u==at_makesuite){
608       if (arg.type==_VECT)
609 	return Equation_compute_size(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr);
610       else
611 	return Equation_compute_size(arg,a,windowhsize,contextptr);
612     }
613     if (u==at_sqrt)
614       return Equation_compute_size(symbolic(at_pow,gen(makevecteur(arg,plus_one_half),_SEQ__VECT)),a,windowhsize,contextptr);
615     if (u==at_division){
616       if (arg.type!=_VECT || arg._VECTptr->size()!=2)
617 	return Equation_compute_size(arg,a,windowhsize,contextptr);
618       gen tmp;
619 #ifdef SMARTPTR64
620       * ((ulonglong * ) &tmp) = ulonglong(new ref_fraction(Tfraction<gen>(arg._VECTptr->front(),arg._VECTptr->back()))) << 16;
621 #else
622       tmp.__FRACptr = new ref_fraction(Tfraction<gen>(arg._VECTptr->front(),arg._VECTptr->back()));
623 #endif
624       tmp.type=_FRAC;
625       return Equation_compute_size(tmp,a,windowhsize,contextptr);
626     }
627     if (u==at_prod){
628       gen n,d;
629       if (rewrite_prod_inv(arg,n,d)){
630 	if (n.is_symb_of_sommet(at_neg))
631 	  return Equation_compute_size(symbolic(at_neg,Tfraction<gen>(-n,d)),a,windowhsize,contextptr);
632 	return Equation_compute_size(Tfraction<gen>(n,d),a,windowhsize,contextptr);
633       }
634     }
635     if (u==at_inv){
636       if ( (is_integer(arg) && is_positive(-arg,contextptr))
637 	   || (arg.is_symb_of_sommet(at_neg)))
638 	return Equation_compute_size(symbolic(at_neg,Tfraction<gen>(plus_one,-arg)),a,windowhsize,contextptr);
639       return Equation_compute_size(Tfraction<gen>(plus_one,arg),a,windowhsize,contextptr);
640     }
641     if (u==at_expr && arg.type==_VECT && arg.subtype==_SEQ__VECT && arg._VECTptr->size()==2 && arg._VECTptr->back().type==_INT_){
642       gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
643       eqwdata vv(Equation_total_size(varg1));
644       gen varg2=eqwdata(0,0,0,0,a,arg._VECTptr->back());
645       vecteur v12(makevecteur(varg1,varg2));
646       v12.push_back(eqwdata(vv.dx,vv.dy,0,vv.y,a,at_expr,0));
647       return gen(v12,_SEQ__VECT);
648     }
649     int llp=int(fl_width("("));
650     int lrp=int(fl_width(")"));
651     int lc=int(fl_width(","));
652     string us=u.ptr()->s;
653     fl_font(cst_greek_translate(us),a.fontsize);
654     int ls=int(fl_width(us.c_str()));
655     fl_font(FL_HELVETICA,a.fontsize);
656     if (isalpha(u.ptr()->s[0]))
657       ls += 2;
658     if (u==at_abs)
659       ls = 2;
660     // special cases first int, sigma, /, ^
661     // and if printed as printsommetasoperator
662     // otherwise print with usual functional notation
663     int x=0;
664     int h=a.fontsize;
665     int y=0;
666     if ((u==at_integrate) || (u==at_sum) ){ // Int
667       int s=1;
668       if (arg.type==_VECT)
669 	s=arg._VECTptr->size();
670       else
671 	arg=vecteur(1,arg);
672       // s==1 -> general case
673       if ( (s==1) || (s==2) ){ // int f(x) dx and sum f(n) n
674 	vecteur v(Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr));
675 	eqwdata vv(Equation_total_size(v[0]));
676 	if (s==1){
677 	  x=a.fontsize;
678 	  Equation_translate(v[0],x,0);
679 	  x += int(fl_width(" dx"));
680 	}
681 	if (s==2){
682 	  if (u==at_integrate){
683 	    x=a.fontsize;
684 	    Equation_translate(v[0],x,0);
685 	    x += vv.dx+int(fl_width(" d"));
686 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
687 	    vv=Equation_total_size(v[1]);
688 	    Equation_translate(v[1],x,0);
689 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
690 	  }
691 	  else {
692 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
693 	    eqwdata v1=Equation_total_size(v[1]);
694 	    x=giacmax(a.fontsize,v1.dx)+a.fontsize/3; // var name size
695 	    Equation_translate(v[1],0,-v1.dy-v1.y);
696 	    Equation_vertical_adjust(v1.dy,-v1.dy,h,y);
697 	    Equation_translate(v[0],x,0);
698 	    x += vv.dx; // add function size
699 	  }
700 	}
701 	if (u==at_integrate){
702 	  x += vv.dx;
703 	  if (h==a.fontsize)
704 	    h+=2*a.fontsize/3;
705 	  if (y==0){
706 	    y=-2*a.fontsize/3;
707 	    h+=2*a.fontsize/3;
708 	  }
709 	}
710 	v.push_back(eqwdata(x,h,0,y,a,u,0));
711 	return gen(v,_SEQ__VECT);
712       }
713       if (s>=3){ // int _a^b f(x) dx
714 	vecteur & intarg=*arg._VECTptr;
715 	gen tmp_l,tmp_u,tmp_f,tmp_x;
716 	attributs aa(a);
717 	if (a.fontsize>=10)
718 	  aa.fontsize -= 2;
719 	tmp_f=Equation_compute_size(intarg[0],a,windowhsize,contextptr);
720 	tmp_x=Equation_compute_size(intarg[1],a,windowhsize,contextptr);
721 	tmp_l=Equation_compute_size(intarg[2],aa,windowhsize,contextptr);
722 	if (s==4)
723 	  tmp_u=Equation_compute_size(intarg[3],aa,windowhsize,contextptr);
724 	x=a.fontsize;
725 	eqwdata vv(Equation_total_size(tmp_l));
726 	Equation_translate(tmp_l,x-2,-vv.y-vv.dy);
727 	vv=Equation_total_size(tmp_l);
728 	Equation_vertical_adjust(vv.dy,vv.y,h,y);
729 	int lx = vv.dx;
730 	if (s==4){
731 	  vv=Equation_total_size(tmp_u);
732 	  Equation_translate(tmp_u,x,a.fontsize-3-vv.y);
733 	  vv=Equation_total_size(tmp_u);
734 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
735 	}
736 	x += max(lx,vv.dx);
737 	Equation_translate(tmp_f,x,0);
738 	vv=Equation_total_size(tmp_f);
739 	Equation_vertical_adjust(vv.dy,vv.y,h,y);
740 	if (u==at_integrate){
741 	  x += vv.dx+int(fl_width(" d"));
742 	  Equation_translate(tmp_x,x,0);
743 	  vv=Equation_total_size(tmp_x);
744 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
745 	  x += vv.dx;
746 	}
747 	else {
748 	  x += vv.dx;
749 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
750 	  vv=Equation_total_size(tmp_x);
751 	  x=max(x,vv.dx)+a.fontsize/3;
752 	  Equation_translate(tmp_x,0,-vv.dy-vv.y);
753 	  Equation_vertical_adjust(vv.dy,-vv.dy,h,y);
754 	}
755 	vecteur res(makevecteur(tmp_f,tmp_x,tmp_l));
756 	if (s==4)
757 	  res.push_back(tmp_u);
758 	res.push_back(eqwdata(x,h,0,y,a,u,0));
759 	return gen(res,_SEQ__VECT);
760       }
761     }
762     if (u==at_limit && arg.type==_VECT){ // limit
763       vecteur & limarg=*arg._VECTptr;
764       int s=limarg.size();
765       if (s>=3){
766 	gen tmp_l,tmp_f,tmp_x,tmp_dir;
767 	attributs aa(a);
768 	if (a.fontsize>=10)
769 	  aa.fontsize -= 2;
770 	tmp_f=Equation_compute_size(limarg[0],a,windowhsize,contextptr);
771 	tmp_x=Equation_compute_size(limarg[1],aa,windowhsize,contextptr);
772 	tmp_l=Equation_compute_size(limarg[2],aa,windowhsize,contextptr);
773 	if (s==4)
774 	  tmp_dir=Equation_compute_size(limarg[3],aa,windowhsize,contextptr);
775 	eqwdata vf(Equation_total_size(tmp_f));
776 	eqwdata vx(Equation_total_size(tmp_x));
777 	eqwdata vl(Equation_total_size(tmp_l));
778 	eqwdata vdir(Equation_total_size(tmp_dir));
779 	int sous=max(vx.dy,vl.dy);
780 	if (s==4)
781 	  Equation_translate(tmp_f,vx.dx+vl.dx+vdir.dx+a.fontsize+4,0);
782 	else
783 	  Equation_translate(tmp_f,vx.dx+vl.dx+a.fontsize+2,0);
784 	Equation_translate(tmp_x,0,-sous-vl.y);
785 	Equation_translate(tmp_l,vx.dx+a.fontsize+2,-sous-vl.y);
786 	if (s==4)
787 	  Equation_translate(tmp_dir,vx.dx+vl.dx+a.fontsize+4,-sous-vl.y);
788 	h=vf.dy;
789 	y=vf.y;
790 	vl=Equation_total_size(tmp_l);
791 	Equation_vertical_adjust(vl.dy,vl.y,h,y);
792 	vecteur res(makevecteur(tmp_f,tmp_x,tmp_l));
793 	if (s==4){
794 	  res.push_back(tmp_dir);
795 	  res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+4+vl.dx+vdir.dx,h,0,y,a,u,0));
796 	}
797 	else
798 	  res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+2+vl.dx,h,0,y,a,u,0));
799 	return gen(res,_SEQ__VECT);
800       }
801     }
802     if ( (u==at_of || u==at_at) && arg.type==_VECT && arg._VECTptr->size()==2 ){
803       // user function, function in 1st arg, arguments in 2nd arg
804       gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
805       eqwdata vv=Equation_total_size(varg1);
806       Equation_vertical_adjust(vv.dy,vv.y,h,y);
807       gen arg2=arg._VECTptr->back();
808       if (u==at_at && xcas_mode(contextptr)!=0){
809 	if (arg2.type==_VECT)
810 	  arg2=gen(addvecteur(*arg2._VECTptr,vecteur(arg2._VECTptr->size(),plus_one)),_SEQ__VECT);
811 	else
812 	  arg2=arg2+plus_one;
813       }
814       gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr);
815       Equation_translate(varg2,vv.dx+llp,0);
816       vv=Equation_total_size(varg2);
817       Equation_vertical_adjust(vv.dy,vv.y,h,y);
818       vecteur res(makevecteur(varg1,varg2));
819       res.push_back(eqwdata(vv.dx+vv.x+lrp,h,0,y,a,u,0));
820       return gen(res,_SEQ__VECT);
821     }
822     if (u==at_pow){
823       // first arg not translated
824       gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
825       eqwdata vv=Equation_total_size(varg);
826       // 1/2 ->sqrt, otherwise as exponent
827       if (arg._VECTptr->back()==plus_one_half){
828 	Equation_translate(varg,a.fontsize,0);
829 	vecteur res(1,varg);
830 	res.push_back(eqwdata(vv.dx+a.fontsize,vv.dy+4,vv.x,vv.y,a,at_sqrt,0));
831 	return gen(res,_SEQ__VECT);
832       }
833       bool needpar=vv.g.type==_FUNC || vv.g.is_symb_of_sommet(at_pow) || need_parenthesis(vv.g);
834       if (needpar)
835 	x=llp;
836       Equation_translate(varg,x,0);
837       Equation_vertical_adjust(vv.dy,vv.y,h,y);
838       vecteur res(1,varg);
839       // 2nd arg translated
840       if (needpar)
841 	x+=vv.dx+lrp;
842       else
843 	x+=vv.dx+1;
844       int arg1dy=vv.dy,arg1y=vv.y;
845       if (a.fontsize>=10){
846 	attributs aa(a);
847 	aa.fontsize -= 2;
848 	varg=Equation_compute_size(arg._VECTptr->back(),aa,windowhsize,contextptr);
849       }
850       else
851 	varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
852       vv=Equation_total_size(varg);
853       Equation_translate(varg,x,arg1y+(3*arg1dy)/4-vv.y);
854       res.push_back(varg);
855       vv=Equation_total_size(varg);
856       Equation_vertical_adjust(vv.dy,vv.y,h,y);
857       x += vv.dx;
858       res.push_back(eqwdata(x,h,0,y,a,u,0));
859       return gen(res,_SEQ__VECT);
860     }
861     if (u==at_factorial){
862       vecteur v;
863       gen varg=Equation_compute_size(arg,a,windowhsize,contextptr);
864       eqwdata vv=Equation_total_size(varg);
865       bool paren=need_parenthesis(vv.g) || vv.g==at_prod || vv.g==at_division || vv.g==at_pow;
866       if (paren)
867 	x+=llp;
868       Equation_translate(varg,x,0);
869       Equation_vertical_adjust(vv.dy,vv.y,h,y);
870       v.push_back(varg);
871       x += vv.dx;
872       if (paren)
873 	x+=lrp;
874       varg=eqwdata(x+4,h,0,y,a,u,0);
875       v.push_back(varg);
876       return gen(v,_SEQ__VECT);
877     }
878     if (u==at_sto){ // A:=B, *it -> B
879       gen varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
880       eqwdata vv=Equation_total_size(varg);
881       Equation_vertical_adjust(vv.dy,vv.y,h,y);
882       Equation_translate(varg,x,0);
883       vecteur v(2);
884       v[1]=varg;
885       x+=vv.dx;
886       x+=ls+3;
887       // first arg not translated
888       varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
889       vv=Equation_total_size(varg);
890       if (need_parenthesis(vv.g))
891 	x+=llp;
892       Equation_translate(varg,x,0);
893       Equation_vertical_adjust(vv.dy,vv.y,h,y);
894       v[0]=varg;
895       x += vv.dx;
896       if (need_parenthesis(vv.g))
897 	x+=lrp;
898       v.push_back(eqwdata(x,h,0,y,a,u,0));
899       return gen(v,_SEQ__VECT);
900     }
901     if (u==at_program && arg._VECTptr->back().type!=_VECT && !arg._VECTptr->back().is_symb_of_sommet(at_local) ){
902       gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
903       eqwdata vv=Equation_total_size(varg);
904       Equation_vertical_adjust(vv.dy,vv.y,h,y);
905       Equation_translate(varg,x,0);
906       vecteur v(2);
907       v[0]=varg;
908       x+=vv.dx;
909       x+=int(fl_width("->"))+3;
910       varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
911       vv=Equation_total_size(varg);
912       Equation_translate(varg,x,0);
913       Equation_vertical_adjust(vv.dy,vv.y,h,y);
914       v[1]=varg;
915       x += vv.dx;
916       v.push_back(eqwdata(x,h,0,y,a,u,0));
917       return gen(v,_SEQ__VECT);
918     }
919     bool binaryop= (u.ptr()->printsommet==&printsommetasoperator) || equalposcomp(binary_op_tab(),u);
920     if ( u!=at_sto && u.ptr()->printsommet!=NULL && !binaryop ){
921       gen tmp=string2gen(g.print(contextptr),false);
922       return Equation_compute_size(symbolic(at_expr,gen(makevecteur(tmp,xcas_mode(contextptr)),_SEQ__VECT)),a,windowhsize,contextptr);
923     }
924      vecteur v;
925      if (!binaryop || arg.type!=_VECT)
926        v=Equation_subsizes(arg,a,windowhsize,contextptr);
927      else
928        v=Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr);
929     iterateur it=v.begin(),itend=v.end();
930     if ( it==itend || (itend-it==1) ){
931       gen gtmp;
932       if (it==itend)
933 	gtmp=Equation_compute_size(gen(vecteur(0),_SEQ__VECT),a,windowhsize,contextptr);
934       else
935 	gtmp=*it;
936       // unary op, shift arg position horizontally
937       eqwdata vv=Equation_total_size(gtmp);
938       bool paren = u!=at_neg || (vv.g!=at_prod && need_parenthesis(vv.g)) ;
939       x=ls+(paren?llp:0);
940       gen tmp=gtmp; Equation_translate(tmp,x,0);
941       x=x+vv.dx+(paren?lrp:0);
942       Equation_vertical_adjust(vv.dy,vv.y,h,y);
943       return gen(makevecteur(tmp,eqwdata(x,h,0,y,a,u,0)),_EQW__VECT);
944     }
945     if (binaryop){ // op (default with par)
946       int currenth=h,largeur=0;
947       iterateur itprec=v.begin();
948       h=0;
949       if (u==at_plus){ // op without parenthesis
950 	llp=0;
951 	lrp=0;
952       }
953       for (;;){
954 	eqwdata vv=Equation_total_size(*it);
955 	if (need_parenthesis(vv.g))
956 	  x+=llp;
957 	if (u==at_plus && it!=v.begin() &&
958 	    (
959 	     (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg)
960 	    ||
961 	     ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) )
962 	     )
963 	    )
964 	  x -= ls;
965 	if (x>windowhsize-vv.dx && x>windowhsize/2 && (itend-it)*vv.dx>windowhsize/2){
966 	  largeur=max(x,largeur);
967 	  x=0;
968 	  if (need_parenthesis(vv.g))
969 	    x+=llp;
970 	  h+=currenth;
971 	  Equation_translate(*it,x,0);
972 	  for (iterateur kt=v.begin();kt!=itprec;++kt)
973 	    Equation_translate(*kt,0,currenth);
974 	  if (y){
975 	    for (iterateur kt=itprec;kt!=it;++kt)
976 	      Equation_translate(*kt,0,-y);
977 	  }
978 	  itprec=it;
979 	  currenth=vv.dy;
980 	  y=vv.y;
981 	}
982 	else {
983 	  Equation_translate(*it,x,0);
984 	  vv=Equation_total_size(*it);
985 	  Equation_vertical_adjust(vv.dy,vv.y,currenth,y);
986 	}
987 	x+=vv.dx;
988 	if (need_parenthesis(vv.g))
989 	  x+=lrp;
990 	++it;
991 	if (it==itend){
992 	  for (iterateur kt=v.begin();kt!=itprec;++kt)
993 	    Equation_translate(*kt,0,currenth+y);
994 	  h+=currenth;
995 	  v.push_back(eqwdata(max(x,largeur),h,0,y,a,u,0));
996 	  // cerr << v << '\n';
997 	  return gen(v,_SEQ__VECT);
998 	}
999 	x += ls+3;
1000       }
1001     }
1002     // normal printing
1003     x=ls+llp;
1004     for (;;){
1005       eqwdata vv=Equation_total_size(*it);
1006       Equation_translate(*it,x,0);
1007       Equation_vertical_adjust(vv.dy,vv.y,h,y);
1008       x+=vv.dx;
1009       ++it;
1010       if (it==itend){
1011 	x+=lrp;
1012 	v.push_back(eqwdata(x,h,0,y,a,u,0));
1013 	return gen(v,_SEQ__VECT);
1014       }
1015       x+=lc;
1016     }
1017   }
1018 
1019   // windowhsize is used for g of type HIST__VECT (history) right justify answers
1020   // Returns either a eqwdata type object (terminal) or a vector
1021   // (of subtype _EQW__VECT or _HIST__VECT)
Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT)1022   gen Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){
1023     fl_font(FL_HELVETICA,a.fontsize);
1024     /**************
1025      * FL_WIDGET  *
1026      **************/
1027     if (g.type==_POINTER_) {
1028       if (g.subtype==_FL_WIDGET_POINTER){
1029 	Fl_Widget * wg=(Fl_Widget *) g._POINTER_val;
1030 	return eqwdata(wg->w(),wg->h(),0,0,a,g);
1031       }
1032 #ifndef __APPLE__
1033       if (g.subtype==_FL_IMAGE_POINTER){
1034 	Fl_Image * ptr=(Fl_Image *) g._POINTER_val;
1035 	return eqwdata(ptr->w(),ptr->h(),0,0,a,g);
1036       }
1037 #endif
1038     }
1039     /***************
1040      *   STRINGS   *
1041      ***************/
1042     if (g.type==_STRNG){
1043       string s;
1044       s=*g._STRNGptr;
1045       string cs;
1046       int ss=s.size();
1047       /* if (!ss)
1048 	 return eqwdata(10,6,0,0,a,g); */
1049       int hsize=0,vsize=0;
1050       bool newline=false;
1051       vecteur res;
1052       gen tmps;
1053       for (int pos=0;pos<ss;++pos){
1054 	char ch=s[pos];
1055 	if (ch=='\n'){
1056 	  newline=true;
1057 	  hsize=max(hsize,int(fl_width((' '+cs).c_str())));
1058 	  tmps=string2gen(cs,false);
1059 	  vsize+=a.fontsize;
1060 	  res.push_back(eqwdata(hsize,a.fontsize,0,-vsize,a,tmps));
1061 	  cs="";
1062 	}
1063 	else
1064 	  cs += ch;
1065       }
1066       hsize=max(hsize,int(fl_width((' '+cs).c_str())));
1067       vsize+=a.fontsize;
1068       tmps=string2gen(cs,false);
1069       if (!newline){
1070 	tmps.subtype=g.subtype;
1071 	return eqwdata(hsize,a.fontsize,0,0,a,tmps);
1072       }
1073       gen tmp=eqwdata(hsize,a.fontsize,0,-vsize,a,tmps);
1074       res.push_back(tmp);
1075       res.push_back(eqwdata(hsize,vsize,0,-vsize,a,at_multistring));
1076       tmp= gen(res,_EQW__VECT);
1077       Equation_translate(tmp,0,vsize);
1078       return tmp;
1079     }
1080     /* SERIES */
1081     if (g.type==_SPOL1){
1082       int sf=series_flags(contextptr);
1083       if (sf & (1<<5) && !(sf & (1<<4))){
1084 	identificateur tt(string(1,series_variable_name(contextptr)));
1085 	gen remains,gg=sparse_poly12gen(*g._SPOL1ptr,tt,remains,!(sf & (1<<6)));
1086 	if ( (sf & (1<<6)) && !is_zero(remains))
1087 	  gg += symb_of(gen("O",contextptr),remains);
1088 	return Equation_compute_size(gg,a,windowhsize,contextptr);
1089       }
1090     }
1091     /*****************
1092      *   FRACTIONS   *
1093      *****************/
1094     if (g.type==_FRAC){
1095       if (is_integer(g._FRACptr->num) && is_positive(-g._FRACptr->num,contextptr))
1096 	return Equation_compute_size(symbolic(at_neg,fraction(-g._FRACptr->num,g._FRACptr->den)),a,windowhsize,contextptr);
1097       gen v1=Equation_compute_size(g._FRACptr->num,a,windowhsize,contextptr);
1098       eqwdata vv1=Equation_total_size(v1);
1099       gen v2=Equation_compute_size(g._FRACptr->den,a,windowhsize,contextptr);
1100       eqwdata vv2=Equation_total_size(v2);
1101       // Center the fraction
1102       int w1=vv1.dx,w2=vv2.dx;
1103       int w=max(w1,w2)+6;
1104       vecteur v(3);
1105       v[0]=v1; Equation_translate(v[0],(w-w1)/2,11-vv1.y);
1106       v[1]=v2; Equation_translate(v[1],(w-w2)/2,7-vv2.dy-vv2.y);
1107       v[2]=eqwdata(w,4+vv1.dy+vv2.dy,0,7-vv2.dy,a,at_division,0);
1108       return gen(v,_SEQ__VECT);
1109     }
1110     /***************
1111      *   VECTORS   *
1112      ***************/
1113     if ( (g.type==_VECT) && !g._VECTptr->empty() ){
1114       if (g.subtype==_GRAPH__VECT){
1115 	string s;
1116 	if (is_graphe(g,s,contextptr))
1117 	  return Equation_compute_size(string2gen(s,false),a,windowhsize,contextptr);
1118       }
1119       if (g.subtype==_SPREAD__VECT)
1120 	return Equation_compute_size(string2gen("spreadsheet",false),a,windowhsize,contextptr);
1121       vecteur v;
1122       const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
1123       int x=0,y=0,h=a.fontsize;
1124       /***************
1125        *   HISTORY   *
1126        ***************/
1127 #if 0
1128       if (g.subtype==_HIST__VECT){
1129 	int l=windowhsize;
1130 	vecteur vplot;
1131 	for (int i=0;it!=itend;++it,++i){
1132 	  gen tmpg(*it);
1133 	  if (!rpn_mode(contextptr) && it->type==_VECT && !it->_VECTptr->empty()){
1134 	    if (it->_VECTptr->front().type==_STRNG)
1135 	      tmpg=makevecteur(it->_VECTptr->front(),string2gen("",false));
1136 	    gen tmpback=it->_VECTptr->back();
1137 	    if (tmpback.type==_POINTER_ && tmpback.subtype==_FL_WIDGET_POINTER && fl_widget_updatepict_function)
1138 	      tmpback = fl_widget_updatepict_function(tmpback);
1139 	    if (tmpback.is_symb_of_sommet(at_pnt) || (tmpback.type==_VECT && !tmpback._VECTptr->empty() && tmpback._VECTptr->back().is_symb_of_sommet(at_pnt)))
1140 	      vplot.push_back(tmpback);
1141 	    if (tmpback.is_symb_of_sommet(at_erase))
1142 	      vplot.clear();
1143 	    gen itfront=it->_VECTptr->front();
1144 	    if (itfront.is_symb_of_sommet(at_expr)){
1145 	      itfront=itfront._SYMBptr->feuille;
1146 	      int mode=xcas_mode(contextptr);
1147 	      if (itfront.type==_VECT && !itfront._VECTptr->empty()){
1148 		mode=itfront._VECTptr->back().val;
1149 		itfront=itfront._VECTptr->front();
1150 	      }
1151 	      if (itfront.type==_STRNG){
1152 		int save_maple_mode=xcas_mode(contextptr);
1153 		xcas_mode(contextptr)=mode;
1154 		try {
1155 		  itfront=gen(*itfront._STRNGptr,contextptr);
1156 		} catch (std::runtime_error & e){
1157 		}
1158 		xcas_mode(contextptr)=save_maple_mode;
1159 	      }
1160 	    }
1161 	  }
1162 	  tmpg.subtype=_SEQ__VECT;
1163 	  vecteur tmp(Equation_subsizes(tmpg,a,windowhsize,contextptr));
1164 	  iterateur jt=tmp.begin(); // this is the question
1165 	  // compute the size of writing the history level i
1166 	  eqwdata w(Equation_total_size(*jt));
1167 	  if (rpn_mode(contextptr)) // ignore question
1168 	    v.push_back(eqwdata(1,1,x,-y,w.eqw_attributs,string2gen("",false)));
1169 	  else {
1170 	    y += w.dy + 2;
1171 	    x = int(fl_width((print_INT_(i)+": ").c_str()));
1172 	    if (l<w.dx+x)
1173 	      l=w.dx+x;
1174 	    Equation_translate(*jt,x,-y-w.y); v.push_back(*jt);
1175 	  }
1176 	  jt=tmp.end()-1; // this is the answer
1177 	  *jt=Equation_change_attributs(*jt,attributs(a.fontsize,a.background,a.text_color+4));
1178 	  w=Equation_total_size(*jt);
1179 	  y += w.dy + 2;
1180 	  x = int(fl_width("    "));
1181 	  l=max(l,w.dx+x);
1182 	  int xshift=x;
1183 	  if (w.dx+4<windowhsize-a.fontsize){
1184 	    if (center_history)
1185 	      xshift=(windowhsize-w.dx-4)/2;
1186 	    else
1187 	      xshift=windowhsize-w.dx-4-a.fontsize;
1188 	  }
1189 	  Equation_translate(*jt,xshift,-y-w.y); v.push_back(*jt);
1190 	}
1191 	v.push_back(eqwdata(l,y,0,-y,a,at_makevector,0));
1192 	// cerr << v << '\n';
1193 	gen res=gen(v,_HIST__VECT); Equation_translate(res,0,y); return res;
1194       } // END HISTORY
1195 #else
1196       if (g.subtype==_HIST__VECT){
1197 	vecteur v;
1198 	v.reserve(g._VECTptr->size());
1199 	// vertical gluing
1200 	int W=0,H=0;
1201 	for (int i=0;it!=itend;++it,++i){
1202 	  gen g=*it;
1203 	  if (g.type==_VECT && g.subtype==_SEQ__VECT)
1204 	    g.subtype=_PRINT__VECT;
1205 	  gen cur_size=Equation_compute_size(g,a,windowhsize,contextptr);
1206 	  eqwdata tmp=Equation_total_size(cur_size);
1207 #if 0
1208 	  int Y,dY;
1209 	  Equation_y_dy(cur_size,Y,dY);
1210 	  Equation_translate(cur_size,0,Y-y-H);
1211 	  H += dY+2;
1212 #else
1213 	  if (ckmatrix(*it))
1214 	    Equation_translate(cur_size,0,tmp.y-y-H+a.fontsize/2);
1215 	  else
1216 	    Equation_translate(cur_size,0,tmp.y-y-H-a.fontsize/2);
1217 	  H += tmp.dy+2;
1218 #endif
1219 	  v.push_back(cur_size);
1220 	  W = giacmax(W,tmp.dx);
1221 	}
1222 	gen mkvect(at_makevector);
1223 	mkvect.subtype=_PRINT__VECT;
1224 	v.push_back(eqwdata(W,H,0,-y-H,a,mkvect,0));
1225 	return gen(v,_EQW__VECT);
1226       } // END HISTORY
1227 #endif
1228       /***************
1229        *   MATRICE   *
1230        ***************/
1231       bool gmat=ckmatrix(g);
1232       vector<int> V; int p=0;
1233       if (!gmat && is_mod_vecteur(*g._VECTptr,V,p) && p!=0){
1234 	gen gm=makemodquoted(unmod(g),p);
1235 	return Equation_compute_size(gm,a,windowhsize,contextptr);
1236       }
1237       vector< vector<int> > M;
1238       if (gmat && is_mod_matrice(*g._VECTptr,M,p) && p!=0){
1239 	gen gm=makemodquoted(unmod(g),p);
1240 	return Equation_compute_size(gm,a,windowhsize,contextptr);
1241       }
1242       if (gmat && g.subtype!=_SEQ__VECT && g.subtype!=_SET__VECT && g.subtype!=_POLY1__VECT && g._VECTptr->front().subtype!=_SEQ__VECT){
1243 	gen mkvect(at_makevector);
1244 	mkvect.subtype=_SEQ__VECT;
1245 	gen mkmat(at_makevector);
1246 	mkmat.subtype=_MATRIX__VECT;
1247 	int nrows,ncols;
1248 	mdims(*g._VECTptr,nrows,ncols);
1249 	if (ncols){
1250 	  vecteur all_sizes;
1251 	  all_sizes.reserve(nrows);
1252 	  vector<int> row_heights(nrows),row_bases(nrows),col_widths(ncols);
1253 	  // vertical gluing
1254 	  for (int i=0;it!=itend;++it,++i){
1255 	    gen tmpg=*it;
1256 	    tmpg.subtype=_SEQ__VECT;
1257 	    vecteur tmp(Equation_subsizes(tmpg,a,max(windowhsize/ncols-a.fontsize,230),contextptr));
1258 	    int h=a.fontsize,y=0;
1259 	    const_iterateur jt=tmp.begin(),jtend=tmp.end();
1260 	    for (int j=0;jt!=jtend;++jt,++j){
1261 	      eqwdata w(Equation_total_size(*jt));
1262 	      Equation_vertical_adjust(w.dy,w.y,h,y);
1263 	      col_widths[j]=max(col_widths[j],w.dx);
1264 	    }
1265 	    if (i)
1266 	      row_heights[i]=row_heights[i-1]+h+a.fontsize;
1267 	    else
1268 	      row_heights[i]=h;
1269 	    row_bases[i]=y;
1270 	    all_sizes.push_back(tmp);
1271 	  }
1272 	  // accumulate col widths
1273 	  col_widths.front() +=(3*a.fontsize)/2;
1274 	  vector<int>::iterator iit=col_widths.begin()+1,iitend=col_widths.end();
1275 	  for (;iit!=iitend;++iit)
1276 	    *iit += *(iit-1)+a.fontsize;
1277 	  // translate each cell
1278 	  it=all_sizes.begin();
1279 	  itend=all_sizes.end();
1280 	  int h,y,prev_h=0;
1281 	  for (int i=0;it!=itend;++it,++i){
1282 	    h=row_heights[i];
1283 	    y=row_bases[i];
1284 	    iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
1285 	    for (int j=0;jt!=jtend;++jt,++j){
1286 	      eqwdata w(Equation_total_size(*jt));
1287 	      if (j)
1288 		Equation_translate(*jt,col_widths[j-1]-w.x,-h-y);
1289 	      else
1290 		Equation_translate(*jt,-w.x+a.fontsize/2,-h-y);
1291 	    }
1292 	    it->_VECTptr->push_back(eqwdata(col_widths.back(),h-prev_h,0,-h,a,mkvect,0));
1293 	    prev_h=h;
1294 	  }
1295 	  all_sizes.push_back(eqwdata(col_widths.back(),row_heights.back(),0,-row_heights.back(),a,mkmat,-row_heights.back()/2));
1296 	  gen all_sizesg=all_sizes; Equation_translate(all_sizesg,0,row_heights.back()/2); return all_sizesg;
1297 	}
1298       } // end matrices
1299       /*************************
1300        *   SEQUENCES/VECTORS   *
1301        *************************/
1302       // horizontal gluing
1303       if (g.subtype!=_PRINT__VECT) x += a.fontsize/2;
1304       int ncols=itend-it;
1305       //ncols=min(ncols,5);
1306       for (;it!=itend;++it){
1307 	gen cur_size=Equation_compute_size(*it,a,
1308 					   max(windowhsize/ncols-a.fontsize,
1309 #ifdef IPAQ
1310 					       200
1311 #else
1312 					       480
1313 #endif
1314 					       ),contextptr);
1315 	eqwdata tmp=Equation_total_size(cur_size);
1316 	Equation_translate(cur_size,x-tmp.x,0); v.push_back(cur_size);
1317 	x=x+tmp.dx+((g.subtype==_PRINT__VECT)?2:a.fontsize);
1318 	Equation_vertical_adjust(tmp.dy,tmp.y,h,y);
1319       }
1320       gen mkvect(at_makevector);
1321       if (g.subtype==_SEQ__VECT)
1322 	mkvect=at_makesuite;
1323       else
1324 	mkvect.subtype=g.subtype;
1325       v.push_back(eqwdata(x,h,0,y,a,mkvect,0));
1326       return gen(v,_EQW__VECT);
1327     } // end sequences
1328     if (g.type==_MOD){
1329       int x=0;
1330       int h=a.fontsize;
1331       int y=0;
1332       bool py=python_compat(contextptr);
1333       int modsize=int(fl_width(py?" mod ":"%"))+4;
1334       bool paren=g._MODptr->type==_SYMB || is_positive(-*g._MODptr,contextptr);
1335       int llp=int(fl_width("("));
1336       int lrp=int(fl_width(")"));
1337       gen varg1=Equation_compute_size(*g._MODptr,a,windowhsize,contextptr);
1338       if (paren) Equation_translate(varg1,llp,0);
1339       eqwdata vv=Equation_total_size(varg1);
1340       Equation_vertical_adjust(vv.dy,vv.y,h,y);
1341       gen arg2=*(g._MODptr+1);
1342       gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr);
1343       if (paren)
1344 	Equation_translate(varg2,vv.dx+modsize+lrp,0);
1345       else
1346 	Equation_translate(varg2,vv.dx+modsize,0);
1347       vv=Equation_total_size(varg2);
1348       Equation_vertical_adjust(vv.dy,vv.y,h,y);
1349       vecteur res(makevecteur(varg1,varg2));
1350       res.push_back(eqwdata(vv.dx+vv.x,h,0,y,a,at_normalmod,0));
1351       return gen(res,_SEQ__VECT);
1352     }
1353     if (g.type==_USER){
1354       if (giac::galois_field *gptr=dynamic_cast<giac::galois_field *>(g._USERptr)){
1355 	if (gptr->a.type==_VECT && gptr->a._VECTptr->size()==1)
1356 	  return Equation_compute_size(makemod(gptr->a._VECTptr->front(),gptr->p),a,windowhsize,contextptr);
1357 	gen g1(g.print(contextptr),contextptr);
1358 	return Equation_compute_size(g1,a,windowhsize,contextptr);
1359       }
1360     }
1361     if (g.type!=_SYMB){
1362       string s=g.print(contextptr);
1363       if (s.size()>2000)
1364 	s=s.substr(0,2000)+"...";
1365       fl_font(cst_greek_translate(s),a.fontsize);
1366       int i=int(fl_width(s.c_str()));
1367       gen tmp=eqwdata(i,a.fontsize,0,0,a,g);
1368       return tmp;
1369     }
1370     /**********************
1371      *  SYMBOLIC HANDLING *
1372      **********************/
1373     vecteur li(lidnt(g));
1374     if (g.type==_SYMB && g._SYMBptr->sommet!=at_prod && g._SYMBptr->sommet!=at_pow && lvar(g)==li && lop(g,at_inv).empty()){
1375       // polynomial check if it has modular coefficients
1376       gen p,modulo;
1377       try {
1378 	p=_symb2poly(makesequence(g,li),contextptr);
1379       }
1380       catch (std::runtime_error & error){
1381 	p=undef;
1382       }
1383       if (p.type==_POLY && has_mod_coeff(p,modulo)){
1384 	polynome & P=*p._POLYptr;
1385 	vector< monomial<gen> >::iterator it=P.coord.begin(),itend=P.coord.end();
1386 	for (;it!=itend;++it){
1387 	  if (it->value.type==_MOD){
1388 	    if (*(it->value._MODptr+1)!=modulo)
1389 	      break;
1390 	    it->value=*it->value._MODptr;
1391 	  }
1392 	}
1393 	if (it==itend){
1394 	  p=makemod(_poly2symb(makesequence(P,li),contextptr),modulo);
1395 	  return Equation_compute_size(p,a,windowhsize,contextptr);
1396 	}
1397       }
1398     }
1399     return Equation_compute_symb_size(g,a,windowhsize,contextptr);
1400     // return Equation_compute_symb_size(aplatir_fois_plus(g),a,windowhsize,contextptr);
1401     // aplatir_fois_plus is a problem for Equation_replace_selection
1402     // because it will modify the structure of the data
1403   }
1404 
Equation_extract_string(const string & cs,int begin_sel,int end_sel)1405   string Equation_extract_string(const string & cs,int begin_sel,int end_sel){
1406     int css=cs.size();
1407     if (!css)
1408       return cs;
1409     int sel0=min(max(0,begin_sel),css-1),sel1=css;
1410     if (end_sel>=0)
1411       sel1=min(end_sel,css);
1412     if (sel0>sel1)
1413       giac::swapint(sel0,sel1);
1414     return cs.substr(sel0,sel1-sel0);
1415   }
1416 
Equation_draw(const eqwdata & e,int x,int y,int rightx,int lowery,Equation * eq,int begin_sel,int end_sel)1417   void Equation_draw(const eqwdata & e,int x,int y,int rightx,int lowery,Equation * eq,int begin_sel,int end_sel){
1418     if ( (e.dx+e.x<x) || (e.x>rightx) || (e.y>y) || e.y+e.dy<lowery)
1419       return; // nothing to draw, out of window
1420     const giac::context * contextptr = get_context(eq);
1421     gen gg=e.g;
1422     bool selected=e.selected && Fl::focus()==eq;
1423     int fontsize=e.eqw_attributs.fontsize;
1424     Fl_Color text_color=Fl_Color(e.eqw_attributs.text_color);
1425     Fl_Color background=Fl_Color(e.eqw_attributs.background);
1426     fl_font(FL_HELVETICA,fontsize);
1427     fl_color(selected?background:text_color);
1428     if (gg.type==_POINTER_) {
1429       // wg->resize(e.x-x,y-e.y-e.dy,e.dx,e.dy);
1430       // wg->draw(); // automatically done if it belongs to the group
1431       return;
1432     }
1433     if (gg.type==_STRNG){
1434       string s;
1435       if (e.active){
1436 	// draw s and the cursor
1437 	s=*gg._STRNGptr;
1438 	int ss=s.size();
1439 	int pos=max(min(eq->active_pos,ss),0);
1440 	if (eq->need_active_parse)
1441 	  s=s.substr(0,pos)+"|"+s.substr(pos,ss-pos);
1442 	else
1443 	  s='"'+s.substr(0,pos)+"|"+s.substr(pos,ss-pos);
1444       }
1445       else {
1446 	if (gg.subtype)
1447 	  s='"'+*gg._STRNGptr;
1448 	else
1449 	  s=' '+*gg._STRNGptr;
1450       }
1451       string cs;
1452       int ss=s.size();
1453       int vsize = fontsize -2,pos;
1454       for (pos=0;pos<ss;++pos){
1455 	char ch=s[pos];
1456 	if (ch=='\n'){
1457 	  check_fl_draw(cs.c_str(),eq->x()+e.x-x,eq->y()+y-e.y+vsize-e.dy,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1458 	  cs="";
1459 	  vsize += fontsize;
1460 	}
1461 	else
1462 	  cs += ch;
1463       }
1464       check_fl_draw(cs.c_str(),eq->x()+e.x-x,eq->y()+y-e.y+vsize-e.dy,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1465       // If selected take care of begin/end selection
1466       int css=cs.size(); // must be >=1 since selected hence not active
1467       if (selected && css){
1468 	int sel0=min(begin_sel+1,css-1),sel1=css;
1469 	if (end_sel>=0)
1470 	  sel1=min(end_sel+1,css);
1471 	if (sel0>sel1)
1472 	  giac::swapint(sel0,sel1);
1473 	int deltax=int(fl_width(cs.substr(0,sel0).c_str()));
1474 	cs=cs.substr(sel0,sel1-sel0);
1475 	int dx=int(fl_width(cs.c_str()));
1476 	fl_color(text_color);
1477 	check_fl_rectf(eq->x()+e.x-x+deltax,eq->y()+y-e.y-e.dy+1,dx,e.dy+3,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1478 	fl_color(background);
1479 	check_fl_draw(cs.c_str(),eq->x()+e.x-x+deltax,eq->y()+y-e.y+vsize-e.dy,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1480       }
1481       return;
1482     }
1483     if (selected){
1484       fl_color(text_color);
1485       check_fl_rectf(eq->x()+e.x-x,eq->y()+y-e.y-e.dy+1,e.dx,e.dy+3,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1486       fl_color(background);
1487     }
1488     string s=gg.print(contextptr);
1489     if (gg.type==_IDNT && !s.empty() && s[0]=='_')
1490       s=s.substr(1,s.size()-1);
1491     if (s.size()>2000)
1492       s=s.substr(0,2000)+"...";
1493     Fl_Font font=cst_greek_translate(s);
1494     if (gg.type==_IDNT && font==FL_HELVETICA
1495 #if !defined(WIN32) && !defined(__APPLE__)
1496 	&& gg!=cst_pi
1497 #endif
1498 	)
1499       font=FL_TIMES_BOLD_ITALIC; // FL_HELVETICA_BOLD_ITALIC;
1500     fl_font(font,fontsize);
1501     // cerr << s.size() << '\n';
1502     check_fl_draw(s.c_str(),eq->x()+e.x-x,eq->y()+y-e.y,eq->clip_x,eq->clip_y,eq->clip_w,eq->clip_h,0,0);
1503     return;
1504   }
1505 
Equation_draw(const gen & g,int x,int y,int rightx,int lowery,Equation * equat)1506   void Equation_draw(const gen & g,int x,int y,int rightx,int lowery,Equation * equat){
1507     const giac::context * contextptr = get_context(equat);
1508     int eqx=equat->x(),eqy=equat->y();
1509     if (g.type==_EQW){ // terminal
1510       eqwdata & e=*g._EQWptr;
1511       Equation_draw(e,x,y,rightx,lowery,equat,equat->begin_sel,equat->end_sel);
1512     }
1513     if (g.type!=_VECT)
1514       return;
1515     vecteur & v=*g._VECTptr;
1516     if (v.empty())
1517       return;
1518     gen tmp=v.back();
1519     if (tmp.type!=_EQW){
1520       cerr << "EQW error:" << v << '\n';
1521       return;
1522     }
1523     eqwdata & w=*tmp._EQWptr;
1524     if ( (w.dx+w.x-x<0) || (w.x>rightx) || (w.y>y) || (w.y+w.dy<lowery) )
1525       return; // nothing to draw, out of window
1526     /*******************
1527      * draw the vector *
1528      *******************/
1529     // v is the vector, w the master operator eqwdata
1530     gen oper=w.g;
1531     bool selected=w.selected && Fl::focus()==equat;
1532     int fontsize=w.eqw_attributs.fontsize;
1533     int background=w.eqw_attributs.background;
1534     int text_color=w.eqw_attributs.text_color;
1535     int x0=w.x;
1536     int y0=w.y; // lower coordinate of the master vector
1537     int y1=y0+w.dy; // upper coordinate of the master vector
1538     if (selected){
1539       fl_color(text_color);
1540       check_fl_rectf(eqx+w.x-x,eqy+y-w.y-w.dy+1,w.dx,w.dy+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1541     }
1542     else {
1543       fl_color(background);
1544       // fl_rectf(w.x-x,y-w.y-w.dy,w.dx,w.dy-2);
1545     }
1546     // draw arguments of v
1547     const_iterateur it=v.begin(),itend=v.end()-1;
1548     if (oper==at_multistring){
1549       const_iterateur it_beg=it,it_end=itend;
1550       if (Equation_multistring_selection(it_beg,it_end,false)){
1551 	// begin_sel and end_sel apply respect. to it_beg and it_end sel. lines
1552 	for (;it!=it_beg;++it)
1553 	  Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,-1,-1);
1554 	if (it_beg==it_end){
1555 	  Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,equat->begin_sel,equat->end_sel);
1556 	  ++it;
1557 	}
1558 	else {
1559 	  Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,equat->begin_sel,-1);
1560 	  ++it;
1561 	  for (;it!=it_end;++it)
1562 	    Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,-1,-1);
1563 	  Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,-1,equat->end_sel);
1564 	  ++it;
1565 	}
1566 	for (;it!=itend;++it)
1567 	  Equation_draw(*it->_EQWptr,x,y,rightx,lowery,equat,-1,-1);
1568 	return;
1569       }
1570     }
1571     if (oper==at_expr && v.size()==3){
1572       Equation_draw(*it,x,y,rightx,lowery,equat);
1573       return;
1574     }
1575     for (;it!=itend;++it)
1576       Equation_draw(*it,x,y,rightx,lowery,equat);
1577     if (oper==at_multistring)
1578       return;
1579     fl_font(FL_HELVETICA,fontsize);
1580     fl_color(selected?background:text_color);
1581     string s;
1582     if (g.subtype==_HIST__VECT){ // For history, we must write history levels
1583       it=v.begin();
1584       int nlevels=(itend-it)/2-1,wlevel;
1585       int skip=2; // int skip=2-rpn_mode(contextptr);
1586       for (int i=0;it!=itend;it+=skip,++i){
1587 	eqwdata tmp=Equation_total_size(*it);
1588 	fl_font(FL_HELVETICA,tmp.eqw_attributs.fontsize);
1589 	fl_color(FL_BLUE);
1590 	// cerr << tmp << '\n';
1591 	int yy;
1592 	// uncommented, seemed previously to be problematic with strings
1593 	if (tmp.hasbaseline)
1594 	  yy=y-tmp.baseline;
1595 	else
1596 	  yy=y-tmp.y-(tmp.dy-tmp.eqw_attributs.fontsize)/2;
1597 	if (yy<0 || yy>y-lowery)
1598 	  continue;
1599 	if (rpn_mode(contextptr))
1600 	  wlevel=nlevels-i;
1601 	else
1602 	  wlevel=i;
1603 	if (wlevel || !rpn_mode(contextptr))
1604 	  check_fl_draw((print_INT_(wlevel)+": ").c_str(),eqx-x,eqy+yy,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1605       }
1606       return; // nothing else to do
1607     }
1608     if (oper.type==_FUNC){
1609       // catch here special cases user function, vect/matr, ^, int, sqrt, etc.
1610       unary_function_ptr & u=*oper._FUNCptr;
1611       if (u==at_at){ // draw brackets around 2nd arg
1612 	gen arg2=v[1]; // 2nd arg of at_of, i.e. what's inside the parenth.
1613 	eqwdata varg2=Equation_total_size(arg2);
1614 	x0=varg2.x;
1615 	y0=varg2.y;
1616 	y1=y0+varg2.dy;
1617 	fontsize=varg2.eqw_attributs.fontsize;
1618 	fl_font(FL_HELVETICA,fontsize);
1619 	if (x0<rightx)
1620 	  check_fl_draw("[",eqx+x0-x-int(fl_width("[")),eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1621 	x0 += varg2.dx ;
1622 	if (x0<rightx)
1623 	  check_fl_draw("]",eqx+x0-x,eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1624 	return;
1625       }
1626       if (u==at_of){ // do we need to draw some parenthesis?
1627 	gen arg2=v[1]; // 2nd arg of at_of, i.e. what's inside the parenth.
1628 	if (arg2.type!=_VECT || arg2._VECTptr->back().type !=_EQW || arg2._VECTptr->back()._EQWptr->g!=at_makesuite){ // Yes (if not _EQW it's a sequence with parent)
1629 	  eqwdata varg2=Equation_total_size(arg2);
1630 	  x0=varg2.x;
1631 	  y0=varg2.y;
1632 	  y1=y0+varg2.dy;
1633 	  fontsize=varg2.eqw_attributs.fontsize;
1634 	  int pfontsize=max(fontsize,(fontsize+(varg2.baseline-varg2.y))/2);
1635 	  fl_font(FL_HELVETICA,pfontsize); // was fontsize
1636 	  if (x0<rightx)
1637 	    check_fl_draw("(",eqx+x0-x-int(fl_width("(")),eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1638 	  x0 += varg2.dx ;
1639 	  if (x0<rightx)
1640 	    check_fl_draw(")",eqx+x0-x,eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1641 	}
1642 	return;
1643       }
1644       if (u==at_makesuite){
1645 	bool paren=v.size()!=2; // Sequences with 1 arg don't show parenthesis
1646 	int pfontsize=max(fontsize,(fontsize+(w.baseline-w.y))/2);
1647 	fl_font(FL_HELVETICA,pfontsize);
1648 	if (paren && x0<rightx)
1649 	  check_fl_draw("(",eqx+x0-x-int(fl_width("("))/2,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1650 	x0 += w.dx;
1651 	if (paren && x0<rightx)
1652 	  check_fl_draw(")",eqx+x0-x-int(fl_width("("))/2,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1653 	// print commas between args
1654 	it=v.begin(),itend=v.end()-2;
1655 	for (;it!=itend;++it){
1656 	  eqwdata varg2=Equation_total_size(*it);
1657 	  fontsize=varg2.eqw_attributs.fontsize;
1658 	  fl_font(FL_HELVETICA,fontsize);
1659 	  if (varg2.x+varg2.dx<rightx)
1660 	    check_fl_draw(",",eqx+varg2.x+varg2.dx-x+1,eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1661 	}
1662 	return;
1663       }
1664       if (u==at_makevector){ // draw [] delimiters for vector/matrices
1665 	if (oper.subtype!=_SEQ__VECT && oper.subtype!=_PRINT__VECT){
1666 	  int decal=1;
1667 	  switch (oper.subtype){
1668 	  case _MATRIX__VECT: decal=2; break;
1669 	  case _SET__VECT: decal=4; break;
1670 	  case _POLY1__VECT: decal=6; break;
1671 	  }
1672 	  if (x0+1<rightx){
1673 	    check_fl_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+1,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1674 	    check_fl_line(eqx+x0-x+decal,eqy+y-y0+1,eqx+x0-x+decal,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1675 	    check_fl_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+fontsize/4,eqy+y-y0+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1676 	    check_fl_line(eqx+x0-x+1,eqy+y-y1+1,eqx+x0-x+fontsize/4,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1677 	  }
1678 	  x0 += w.dx ;
1679 	  if (x0-1<rightx){
1680 	    check_fl_line(eqx+x0-x-1,eqy+y-y0+1,eqx+x0-x-1,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1681 	    check_fl_line(eqx+x0-x-decal,eqy+y-y0+1,eqx+x0-x-decal,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1682 	    check_fl_line(eqx+x0-x-1,eqy+y-y0+1,eqx+x0-x-fontsize/4,eqy+y-y0+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1683 	    check_fl_line(eqx+x0-x-1,eqy+y-y1+1,eqx+x0-x-fontsize/4,eqy+y-y1+1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1684 	  }
1685 	} // end if oper.subtype!=SEQ__VECT
1686 	if (oper.subtype!=_MATRIX__VECT && oper.subtype!=_PRINT__VECT){
1687 	  // print commas between args
1688 	  it=v.begin(),itend=v.end()-2;
1689 	  for (;it!=itend;++it){
1690 	    eqwdata varg2=Equation_total_size(*it);
1691 	    fontsize=varg2.eqw_attributs.fontsize;
1692 	    fl_font(FL_HELVETICA,fontsize);
1693 	    if (varg2.x+varg2.dx<rightx)
1694 	      check_fl_draw(",",eqx+varg2.x+varg2.dx-x+1,eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1695 	  }
1696 	}
1697 	return;
1698       }
1699       int lpsize=int(fl_width("("));
1700       int rpsize=int(fl_width(")"));
1701       eqwdata tmp=Equation_total_size(v.front()); // tmp= 1st arg eqwdata
1702       if (u==at_sto)
1703 	tmp=Equation_total_size(v[1]);
1704       x0=w.x-x;
1705       y0=y-w.baseline;
1706       if (u==at_pow){
1707 	if (!need_parenthesis(tmp.g)&& tmp.g!=at_pow && tmp.g!=at_prod && tmp.g!=at_division)
1708 	  return;
1709 	if (tmp.g==at_pow){
1710 	  fontsize=tmp.eqw_attributs.fontsize+2;
1711 	  fl_font(FL_HELVETICA,fontsize);
1712 	}
1713 	if (tmp.x-lpsize<rightx)
1714 	  check_fl_draw("(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1715 	if (tmp.x+tmp.dx<rightx)
1716 	  check_fl_draw(")",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1717 	return;
1718       }
1719       if (u==at_program){
1720 	if (tmp.x+tmp.dx<rightx)
1721 	  check_fl_draw("->",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1722 	return;
1723       }
1724       if (u==at_sum){
1725 	if (x0<rightx){
1726 	  check_fl_line(eqx+x0,eqy+y0,eqx+x0+(2*fontsize)/3,eqy+y0,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1727 	  check_fl_line(eqx+x0,eqy+y0-fontsize,eqx+x0+(2*fontsize)/3,eqy+y0-fontsize,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1728 	  check_fl_line(eqx+x0,eqy+y0,eqx+x0+fontsize/2,eqy+y0-fontsize/2,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1729 	  check_fl_line(eqx+x0+fontsize/2,eqy+y0-fontsize/2,eqx+x0,eqy+y0-fontsize,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1730 	  if (v.size()>2){ // draw the =
1731 	    eqwdata ptmp=Equation_total_size(v[1]);
1732 	    if (ptmp.x+ptmp.dx<rightx)
1733 	      check_fl_draw("=",eqx+ptmp.x+ptmp.dx-x-2,eqy+y-ptmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1734 	  }
1735 	}
1736 	return;
1737       }
1738       if (u==at_abs){
1739 	y0 =1+y-w.y;
1740 	int h=w.dy;
1741 	if (x0<rightx){
1742 	  check_fl_line(eqx+x0+2,eqy+y0-1,eqx+x0+2,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1743 	  check_fl_line(eqx+x0+1,eqy+y0-1,eqx+x0+1,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1744 	  check_fl_line(eqx+x0+w.dx-1,eqy+y0-1,eqx+x0+w.dx-1,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1745 	  check_fl_line(eqx+x0+w.dx,eqy+y0-1,eqx+x0+w.dx,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1746 	}
1747 	return;
1748       }
1749       if (u==at_sqrt){
1750 	y0 =1+y-w.y;
1751 	int h=w.dy;
1752 	if (x0<rightx){
1753 	  check_fl_line(eqx+x0+2,eqy+y0-h/2,eqx+x0+fontsize/2,eqy+y0-1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1754 	  check_fl_line(eqx+x0+fontsize/2,eqy+y0-1,eqx+x0+fontsize,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1755 	  check_fl_line(eqx+x0+fontsize,eqy+y0-h+3,eqx+x0+w.dx-1,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1756 	  ++y0;
1757 	  check_fl_line(eqx+x0+2,eqy+y0-h/2,eqx+x0+fontsize/2,eqy+y0-1,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1758 	  check_fl_line(eqx+x0+fontsize/2,eqy+y0-1,eqx+x0+fontsize,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1759 	  check_fl_line(eqx+x0+fontsize,eqy+y0-h+3,eqx+x0+w.dx-1,eqy+y0-h+3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1760 	}
1761 	return;
1762       }
1763       if (u==at_factorial){
1764 	check_fl_draw("!",eqx+w.x+w.dx-4-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1765 	if (!need_parenthesis(tmp.g)
1766 	    && tmp.g!=at_pow && tmp.g!=at_prod && tmp.g!=at_division
1767 	    )
1768 	  return;
1769 	if (tmp.x-lpsize<rightx)
1770 	  check_fl_draw("(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1771 	if (tmp.x+tmp.dx<rightx)
1772 	  check_fl_draw(")",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1773 	return;
1774       }
1775       if (u==at_integrate){
1776 	x0+=2;
1777 	y0+=fontsize/2;
1778 	if (x0<rightx){
1779 	  fl_arc(eqx+x0,eqy+y0,fontsize/3,fontsize/3,180,360);
1780 	  check_fl_line(eqx+x0+fontsize/3,eqy+y0,eqx+x0+fontsize/3,eqy+y0-2*fontsize+4,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1781 	  fl_arc(eqx+x0+fontsize/3,eqy+y0-2*fontsize+3,fontsize/3,fontsize/3,0,180);
1782 	}
1783 	if (v.size()!=2){ // if arg has size > 1 draw the d
1784 	  eqwdata ptmp=Equation_total_size(v[1]);
1785 	  if (ptmp.x<rightx)
1786 	    check_fl_draw(" d",eqx+ptmp.x-x-int(fl_width(" d")),eqy+y-ptmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1787 	}
1788 	else {
1789 	  eqwdata ptmp=Equation_total_size(v[0]);
1790 	  if (ptmp.x+ptmp.dx<rightx)
1791 	    check_fl_draw(" dx",eqx+ptmp.x+ptmp.dx-x,eqy+y-ptmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1792 	}
1793 	return;
1794       }
1795       if (u==at_division){
1796 	if (x0<rightx){
1797 	  int yy=eqy+y0-6;
1798 	  check_fl_line(eqx+x0+2,yy,eqx+x0+w.dx-2,yy,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1799 	  ++yy;
1800 	  check_fl_line(eqx+x0+2,yy,eqx+x0+w.dx-2,yy,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1801 	}
1802 	return;
1803       }
1804       if (u==at_limit && v.size()>=4){
1805 	if (x0<rightx)
1806 	  check_fl_draw("lim",eqx+w.x-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1807 	gen arg2=v[1]; // 2nd arg of limit, i.e. the variable
1808 	if (arg2.type==_EQW){
1809 	  eqwdata & varg2=*arg2._EQWptr;
1810 	  if (varg2.x+varg2.dx+2<rightx)
1811 	    check_fl_draw("->",eqx+varg2.x+varg2.dx+2-x,eqy+y-varg2.y,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1812 	}
1813 	if (v.size()>=5){
1814 	  arg2=v[2]; // 3rd arg of lim, the point, draw a comma after if dir.
1815 	  if (arg2.type==_EQW){
1816 	    eqwdata & varg2=*arg2._EQWptr;
1817 	    if (varg2.x+varg2.dx<rightx)
1818 	      check_fl_draw(",",eqx+varg2.x+varg2.dx-x,eqy+y-varg2.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1819 	  }
1820 	}
1821 	return;
1822       }
1823       bool parenthesis=true;
1824       string opstring(",");
1825       if (u.ptr()->printsommet==&printsommetasoperator || equalposcomp(binary_op_tab(),u) ){
1826 	if (u==at_normalmod && python_compat(contextptr))
1827 	  opstring=" mod";
1828 	else
1829 	  opstring=u.ptr()->s;
1830       }
1831       else {
1832 	if (u==at_sto)
1833 	  opstring=":=";
1834 	parenthesis=false;
1835       }
1836       // int yy=y0; // y0 is the lower coordinate of the whole eqwdata
1837       // int opsize=int(fl_width(opstring.c_str()))+3;
1838       it=v.begin();
1839       itend=v.end()-1;
1840       // Reminder: here tmp is the 1st arg eqwdata, w the whole eqwdata
1841       if ( (itend-it==1) && ( (u==at_neg)
1842 			      || (u==at_plus) // uncommented for +infinity
1843 			      ) ){
1844 	if (u==at_neg &&need_parenthesis(tmp.g) && tmp.g!=at_prod){
1845 	  if (tmp.x-lpsize<rightx)
1846 	    check_fl_draw("(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1847 	  if (tmp.x+tmp.dx<rightx)
1848 	    check_fl_draw(")",eqx+tmp.x-x+tmp.dx,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1849 	}
1850 	if (w.x<rightx){
1851 #if 1
1852 	  if (u==at_neg){
1853 	    int xx=w.x-x;
1854 	    int cx=eqx+xx+2,cy=eqy+y-w.baseline-fontsize/3,ch=giacmax(2,(fontsize+5)/6);
1855 	    if (fontsize<16) --cx; else ++cy;
1856 	    if (fontsize<12) --cx;
1857 	    if (fontsize>23) ++cx;
1858 	    if (fontsize>29) ++cx;
1859 	    if (fontsize>37) ++cx;
1860 	    fl_line(cx-ch,cy,cx+ch-1,cy);
1861 	    --cy;
1862 	    fl_line(cx-ch,cy,cx+ch-1,cy);
1863 	    if (fontsize>13){
1864 	      --cy;
1865 	      fl_line(cx-ch,cy,cx+ch-1,cy);
1866 	      if (fontsize>23){
1867 		cy+=3;
1868 		fl_line(cx-ch,cy,cx+ch-1,cy);
1869 	      }
1870 	    }
1871 	  }
1872 	  else
1873 	    check_fl_draw(u.ptr()->s,eqx+w.x-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1874 #else
1875 	  fl_font(FL_TIMES_BOLD,fontsize);
1876 	  check_fl_draw(u.ptr()->s,eqx+w.x-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1877 #endif
1878 	}
1879 	return;
1880       }
1881       // write first open parenthesis
1882       if (u==at_plus)
1883 	parenthesis=false;
1884       else {
1885 	if (parenthesis && need_parenthesis(tmp.g)){
1886 	  if (w.x<rightx){
1887 	    int pfontsize=max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2);
1888 	    fl_font(FL_HELVETICA,pfontsize);
1889 	    check_fl_draw("(",eqx+w.x-x,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1890 	    fl_font(FL_HELVETICA,fontsize);
1891 	  }
1892 	}
1893       }
1894       for (;;){
1895 	// write close parenthesis at end
1896 	int xx=tmp.dx+tmp.x-x;
1897 	if (parenthesis && need_parenthesis(tmp.g)){
1898 	  if (xx<rightx){
1899 	    int pfontsize=min(max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2),fontsize*2);
1900 	    int deltapary=(2*(pfontsize-fontsize))/3;
1901 	    fl_font(FL_HELVETICA,pfontsize);
1902 	    check_fl_draw(")",eqx+xx,eqy+y-tmp.baseline+deltapary,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1903 	    fl_font(FL_HELVETICA,fontsize);
1904 	  }
1905 	  xx +=rpsize;
1906 	}
1907 	++it;
1908 	if (it==itend){
1909 	  if (u.ptr()->printsommet==&printsommetasoperator || u==at_sto || equalposcomp(binary_op_tab(),u))
1910 	    return;
1911 	  else
1912 	    break;
1913 	}
1914 	// write operator
1915 	if (u==at_prod){
1916 #if 1
1917 	  // check_fl_draw(".",eqx+xx+3,eqy+y-tmp.baseline-fontsize/3,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1918 	  fl_font(FL_TIMES_ITALIC,fontsize);
1919 	  check_fl_draw(opstring.c_str(),eqx+xx+1,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1920 #else
1921 	  int cx=eqx+xx+5,cy=-3+eqy+y-tmp.baseline-fontsize/3,ch=giacmax(2,fontsize/6);
1922 	  // fl_line(cx-ch+1,cy,cx+ch-1,cy); // horizontal (smaller to avoid confusion with -)
1923 	  if (fontsize<16) --cx;
1924 	  if (fontsize<12) --cx;
1925 	  fl_line(cx,cy+ch,cx,cy-ch);
1926 	  fl_line(cx-ch,cy+ch,cx+ch,cy-ch);
1927 	  fl_line(cx-ch,cy-ch,cx+ch,cy+ch);
1928 #endif
1929 	}
1930 	else {
1931 	  gen tmpgen;
1932 	  if (u==at_plus && (
1933 			     (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg)
1934 			     ||
1935 			     ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) )
1936 			     )
1937 	      )
1938 	    ;
1939 	  else {
1940 	    if (xx+1<rightx)
1941 	      // fl_draw(opstring.c_str(),xx+1,y-tmp.y-tmp.dy/2+fontsize/2);
1942 	      check_fl_draw(opstring.c_str(),eqx+xx+1,eqy+y-tmp.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1943 	  }
1944 	}
1945 	// write right parent, update tmp
1946 	tmp=Equation_total_size(*it);
1947 	if (parenthesis && (need_parenthesis(tmp.g)) ){
1948 	  if (tmp.x-lpsize<rightx){
1949 	    int pfontsize=min(max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2),fontsize*2);
1950 	    int deltapary=(2*(pfontsize-fontsize))/3;
1951 	    fl_font(FL_HELVETICA,pfontsize);
1952 	    check_fl_draw("(",eqx+tmp.x-pfontsize*lpsize/fontsize-x,eqy+y-tmp.baseline+deltapary,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1953 	    fl_font(FL_HELVETICA,fontsize);
1954 	  }
1955 	}
1956       } // end for (;;)
1957       if (w.x<rightx){
1958 	s = u.ptr()->s;
1959 	fl_font(cst_greek_translate(s),fontsize);
1960 	s += '(';
1961 	check_fl_draw(s.c_str(),eqx+w.x-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1962 	fl_font(FL_HELVETICA,fontsize);
1963       }
1964       if (w.x+w.dx-rpsize<rightx)
1965 	check_fl_draw(")",eqx+w.x+w.dx-x-rpsize,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1966       return;
1967     }
1968     s=oper.print(contextptr);
1969     if (w.x<rightx){
1970       fl_font(cst_greek_translate(s),fontsize);
1971       check_fl_draw(s.c_str(),eqx+w.x-x,eqy+y-w.baseline,equat->clip_x,equat->clip_y,equat->clip_w,equat->clip_h,0,0);
1972       fl_font(FL_HELVETICA,fontsize);
1973     }
1974   }
1975 
draw()1976   void Equation::draw(){
1977     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
1978     //cout << clip_x << " " << clip_y << " " << clip_w << " " << clip_h << '\n';
1979     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
1980     fl_color(attr.background);
1981     fl_rectf(clip_x, clip_y, clip_w, clip_h);
1982     fl_color(attr.text_color);
1983     fl_rect(x(), y(), w(), h());
1984     Equation_draw(data,xleft,ytop,xleft+w()-vscroll->w(),ytop-h()-hscroll->h(),this);
1985     Fl_Group::draw_children();
1986     fl_pop_clip();
1987   }
1988 
Equation_box_sizes(const gen & g,int & l,int & h,int & x,int & y,attributs & attr,bool & selected,bool search_active=false)1989   bool Equation_box_sizes(const gen & g,int & l,int & h,int & x,int & y,attributs & attr,bool & selected,bool search_active=false){
1990     if (g.type==_EQW){
1991       eqwdata & w=*g._EQWptr;
1992       x=w.x;
1993       y=w.y;
1994       l=w.dx;
1995       h=w.dy;
1996       if (search_active)
1997 	selected=w.active;
1998       else
1999 	selected=w.selected;
2000       attr=w.eqw_attributs;
2001       return true;
2002     }
2003     else {
2004       if (g.type!=_VECT || g._VECTptr->empty() ){
2005 	l=0;
2006 	h=0;
2007 	x=0;
2008 	y=0;
2009 	attr=attributs(0,0,0);
2010 	selected=false;
2011 	return true;
2012       }
2013       gen & g1=g._VECTptr->back();
2014       Equation_box_sizes(g1,l,h,x,y,attr,selected,search_active);
2015       return false;
2016     }
2017   }
2018 
2019   // Set the scrollbars according to data, xleft, ytop
setscroll()2020   void Equation::setscroll(){
2021     int w=this->w()-vscroll->w();
2022     int h=this->h()-hscroll->h();
2023     redraw();
2024     eqwdata e=Equation_total_size(data);
2025     if (e.dx>w){
2026       xleft=max(e.x,xleft);
2027       xleft=min(e.x+e.dx-w,xleft);
2028       hscroll->value(xleft-e.x,w,0,e.dx);
2029       hscroll->show();
2030     }
2031     else {
2032       xleft = e.x - (w-e.dx)/2;
2033       hscroll->value(0,1,0,1);
2034       hscroll->hide();
2035     }
2036     if (e.dy>h){
2037       ytop=max(e.y+h,ytop);
2038       ytop=min(e.y+e.dy,ytop);
2039       vscroll->value(e.dy+e.y-ytop,h,0,e.dy);
2040       vscroll->show();
2041     }
2042     else {
2043       ytop = e.y + (e.dy + h)/2;
2044       vscroll->value(0,1,0,1);
2045       vscroll->hide();
2046     }
2047   }
2048 
Equation_cb_scroll(Fl_Widget * w,void *)2049   void Equation_cb_scroll(Fl_Widget * w, void*) {
2050     Equation_Scrollbar * s=dynamic_cast<Equation_Scrollbar *>(w);
2051     if (!s)
2052       return;
2053     if (s->vertical){
2054       eqwdata e=Equation_total_size(s->eqwptr->data);
2055       s->eqwptr->ytop=e.dy+e.y-s->value();
2056     }
2057     else
2058       s->eqwptr->xleft=s->value();
2059     s->eqwptr->setscroll();
2060     s->eqwptr->redraw();
2061   }
2062 
2063   // select or deselect part of the current eqution
2064   // This is done *in place*
Equation_select(gen & g,bool select,bool active_search)2065   void Equation_select(gen & g,bool select,bool active_search){
2066     if (g.type==_EQW){
2067       eqwdata & e=*g._EQWptr;
2068       if (active_search)
2069 	e.active=select;
2070       else
2071 	e.selected=select;
2072     }
2073     if (g.type!=_VECT)
2074       return;
2075     vecteur & v=*g._VECTptr;
2076     iterateur it=v.begin(),itend=v.end();
2077     for (;it!=itend;++it)
2078       Equation_select(*it,select,active_search);
2079   }
2080 
deselect()2081   void Equation::deselect(){
2082     begin_sel=-1;
2083     end_sel=-1;
2084     Equation_select(data,false);
2085     redraw();
2086   }
2087 
select()2088   void Equation::select(){
2089     begin_sel=-1;
2090     end_sel=-1;
2091     Equation_select(data,true);
2092     adjust_xy_sel();
2093     redraw();
2094   }
2095 
fl_select()2096   void Equation::fl_select(){
2097     const giac::context * contextptr = get_context(this);
2098     gen g=get_selection();
2099     string s;
2100     if (g.type==_STRNG) s=*g._STRNGptr; else s=g.print(contextptr);
2101     Fl::selection(*this,s.c_str(),s.size());
2102     if (cb_select)
2103       cb_select(s.c_str());
2104   }
2105 
2106   // check if interval xmin..xmax and x1..x2 have a non empty intersection
interval_crossing(int xmin,int xmax,int x1,int x2)2107   bool interval_crossing(int xmin,int xmax,int x1,int x2){
2108     if (xmax<x1 || xmin>x2)
2109       return false;
2110     return true;
2111   }
2112 
2113   // Select in g the subrectangle xmin,ymin,xmax,ymax
Equation_select_rectangle(gen & g,int x1,int y1,int x2,int y2,Equation * eq)2114   void Equation_select_rectangle(gen & g,int x1,int y1,int x2,int y2,Equation * eq){
2115     int xmin=min(x1,x2),xmax=max(x1,x2),ymin=min(y1,y2),ymax=max(y1,y2);
2116     if (g.type==_EQW) {
2117       Equation_select(g,true);
2118       if (g._EQWptr->g.type==_STRNG){
2119 	// compute begin/end_sel
2120 	if (y1<y2){
2121 	  giac::swapint(y1,y2);
2122 	  giac::swapint(x1,x2);
2123 	}
2124 	eq->begin_sel=Equation_binary_search_pos(*g._EQWptr,x1,y1);
2125 	eq->end_sel=Equation_binary_search_pos(*g._EQWptr,x2,y2);
2126       }
2127       return;
2128     }
2129     if (g.type!=_VECT)
2130       return;
2131     vecteur & v=*g._VECTptr;
2132     // Find the first element of v containing the whole rectangle
2133     iterateur it=v.begin(),itend=v.end()-1,last_sel_it;
2134     for (;it!=itend;++it){
2135       int x,y,l,h;
2136       attributs attr(0,0,0);
2137       bool selected;
2138       Equation_box_sizes(*it,l,h,x,y,attr,selected);
2139       if ( (x<=xmin) && (y<=ymin) && (xmax<=x+l) && (ymax<=y+h) ){
2140 	Equation_select_rectangle(*it,x1,y1,x2,y2,eq);
2141 	return;
2142       }
2143     }
2144     // None, then we select each element that crosses the rectangle
2145     bool selectall=true,find_first_sel=false,find_last_sel=false;
2146     if (itend->type==_EQW && itend->_EQWptr->g==at_multistring){
2147       if (y1<y2){
2148 	giac::swapint(y1,y2);
2149 	giac::swapint(x1,x2);
2150       }
2151       find_first_sel=true;
2152       selectall=false;
2153     }
2154     it=v.begin();
2155     for (;it!=itend;++it){
2156       int x,y,l,h;
2157       attributs attr(0,0,0);
2158       bool selected;
2159       Equation_box_sizes(*it,l,h,x,y,attr,selected);
2160       bool xcross=interval_crossing(xmin,xmax,x,x+l),ycross=interval_crossing(ymin,ymax,y,y+h);
2161       if ( xcross && ycross ){
2162 	Equation_select(*it,true);
2163 	last_sel_it=it;
2164 	if (find_first_sel){
2165 	  find_first_sel=false;
2166 	  find_last_sel=true;
2167 	  eq->begin_sel=Equation_binary_search_pos(*it->_EQWptr,x1,y1);
2168 	}
2169       }
2170       else {
2171 	if (ycross && g.subtype==_HIST__VECT){
2172 	  Equation_select(*it,true);
2173 	  last_sel_it=it;
2174 	}
2175 	else
2176 	  selectall=false;
2177       }
2178     }
2179     if (find_last_sel)
2180       eq->end_sel=Equation_binary_search_pos(*last_sel_it->_EQWptr,x2,y2);
2181     if (selectall)
2182       Equation_select(g,true);
2183   }
2184 
select_rectangle(int x,int y)2185   void Equation::select_rectangle(int x,int y){
2186     // x,y are the end of the mouse selection
2187     Equation_select_rectangle(data,xsel,ysel,x,y,this);
2188   }
2189 
2190   // return true if g has some selection inside
Equation_adjust_xy(const gen & g,int & xleft,int & ytop,int & xright,int & ybottom,bool active_search=false)2191   bool Equation_adjust_xy(const gen & g,int & xleft,int & ytop,int & xright,int & ybottom,bool active_search=false){
2192     int x,y,w,h;
2193     attributs f(0,0,0);
2194     bool selected;
2195     Equation_box_sizes(g,w,h,x,y,f,selected,active_search);
2196     if ( (g.type==_EQW__VECT) || selected ){ // terminal or selected
2197       xleft=x;
2198       ybottom=y;
2199       if (selected){ // g is selected
2200 	ytop=y+h;
2201 	xright=x+w;
2202 	return true;
2203       }
2204       else { // no selection
2205 	xright=x;
2206 	ytop=y;
2207 	return false;
2208       }
2209     }
2210     if (g.type!=_VECT)
2211       return false;
2212     // last not selected, recurse
2213     iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end()-1;
2214     for (;it!=itend;++it){
2215       if (Equation_adjust_xy(*it,xleft,ytop,xright,ybottom,active_search))
2216 	return true;
2217     }
2218     return false;
2219   }
2220 
adjust_xy()2221   void Equation::adjust_xy(){
2222     // recalculate xsel, ysel to begin top of selection
2223     // and xcur, ycur to end bottom of selection
2224     Equation_adjust_xy(data,xsel,ysel,xcur,ycur);
2225   }
2226 
adjust_xy_sel()2227   void Equation::adjust_xy_sel(){
2228     // same + recalc xleft
2229     Equation_adjust_xy(data,xsel,ysel,xcur,ycur);
2230     if ((xcur>xleft+w()) || (xsel<xleft) )
2231       xleft=max(xsel-w()/2,0);
2232     if ( ycur < ytop-h() || ysel >ytop )
2233       ytop=ysel;
2234     // recalc scrollbars
2235     setscroll();
2236   }
2237 
2238   // Find i position of first selected item in it..itend
Equation_find_multistring_pos(const_iterateur it,const_iterateur itend,int & i,int & nrows,bool active_search=false)2239   bool Equation_find_multistring_pos(const_iterateur it,const_iterateur itend,int & i,int &nrows,bool active_search=false){
2240     int t;
2241     nrows=itend-it;
2242     for (i=0;it!=itend;++it,++i){ // find row
2243       if (it->type!=_EQW || it->_EQWptr->g.type!=_STRNG)
2244 	return false;
2245       if (Equation_adjust_xy(*it,t,t,t,t,active_search))
2246 	break;
2247     }
2248     if (it==itend)
2249       return false;
2250     return true;
2251   }
2252 
2253   // Assumes it points to the beginning of a string, selects position i
Equation_select_multistring_pos(iterateur it,int i)2254   void Equation_select_multistring_pos(iterateur it,int i){
2255     iterateur jt=(it+i);
2256     Equation_select(*jt,true);
2257   }
2258 
2259   // find selection position in it..itend
2260   // Return true if at least 1 item is selected
Equation_find_vector_pos(const_iterateur it,const_iterateur itend,int & i,int & nrows)2261   bool Equation_find_vector_pos(const_iterateur it,const_iterateur itend,int & i,int &nrows){
2262     int t;
2263     nrows=itend-it;
2264     for (i=0;it!=itend;++it,++i){ // find row in i
2265       if (Equation_adjust_xy(*it,t,t,t,t))
2266 	break;
2267     }
2268     if (it==itend){
2269       --i;
2270       return false;
2271     }
2272     return true;
2273   }
2274 
2275   // Find i,j position of first selected item in it..itend
Equation_find_matrix_pos(const_iterateur it,const_iterateur itend,int & i,int & j,int & nrows,int & ncols,bool active_search=false)2276   bool Equation_find_matrix_pos(const_iterateur it,const_iterateur itend,int & i,int &j,int &nrows,int & ncols,bool active_search=false){
2277     // (incomplete) check for a matrix: the first element must be a vector
2278     if (it->type!=_VECT || it->_VECTptr->empty() )
2279       return false;
2280     gen & tmp=it->_VECTptr->back();
2281     if (tmp.type!=_EQW || tmp._EQWptr->g !=at_makevector)
2282       return false;
2283     // find selection position and move down
2284     int t;
2285     nrows=itend-it;
2286     int c=it->_VECTptr->size();
2287     const_iterateur it0=it;
2288     for (;it0!=itend;++it0){ // more complete matrix check
2289       if (it0->type!=_VECT || int(it0->_VECTptr->size())!=c)
2290 	return false;
2291     }
2292     for (i=0;it!=itend;++it,++i){ // find row
2293       if (Equation_adjust_xy(*it,t,t,t,t,active_search))
2294 	break;
2295     }
2296     if (it==itend || it->type!=_VECT )
2297       return false;
2298     // find column
2299     const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end()-1;
2300     ncols=jtend-jt;
2301     for (j=0;jt!=jtend;++jt,++j){
2302       if (Equation_adjust_xy(*jt,t,t,t,t,active_search))
2303 	break;
2304     }
2305     if (jt==jtend)
2306       return false;
2307     return true;
2308   }
2309 
2310   // Assumes it points to the beginning of the matrix, selects position i,j
Equation_select_matrix_pos(iterateur it,int i,int j)2311   void Equation_select_matrix_pos(iterateur it,int i,int j){
2312     iterateur jt=(it+i)->_VECTptr->begin()+j;
2313     Equation_select(*jt,true);
2314   }
2315 
2316   // increase selection up (like HP49 eqw Up key)
2317   // x,y is the cursor position
Equation_select_up(gen & g,int x,int y,int mode)2318   void Equation_select_up(gen & g,int x,int y,int mode){
2319     if (g.type==_EQW){ // terminal -> select
2320       g._EQWptr->selected=true;
2321       return;
2322     }
2323     if (g.type!=_VECT || g._VECTptr->empty())
2324       return;
2325     vecteur & v=*g._VECTptr;
2326     iterateur it=v.begin(),itend=v.end()-1;
2327     if (v.back().type!=_EQW)
2328       setsizeerr();
2329     eqwdata & w=*v.back()._EQWptr;
2330     int i,j,nrows,ncols;
2331     if ( mode && w.g==at_makevector && Equation_find_matrix_pos(it,itend,i,j,nrows,ncols) ){
2332       --i;
2333       if (i<0)
2334 	i=nrows-1;
2335       Equation_select(g,false);
2336       Equation_select_matrix_pos(it,i,j);
2337       return;
2338     }
2339     if ( mode && w.g==at_multistring && Equation_find_multistring_pos(it,itend,i,nrows) ){
2340       --i;
2341       if (i<0)
2342 	i=nrows-1;
2343       Equation_select(g,false);
2344       Equation_select_multistring_pos(it,i);
2345       return;
2346     }
2347     // find a box containing the cursor
2348     int x0,y0,w0,h0;
2349     attributs attr(0,0,0);
2350     bool selected;
2351     for (;it!=itend;++it){
2352       Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected);
2353       if ( (x0<x) && (x0+w0>=x) && (y0<=y) && (y0+h0>=y) )
2354 	break;
2355     }
2356     if (it==itend)
2357       return;
2358     // if the box is selected select g else recurse
2359     if (selected)
2360       Equation_select(g,true);
2361     else
2362       Equation_select_up(*it,x,y,mode);
2363   }
2364 
select_up(int mode)2365   void Equation::select_up(int mode){
2366     const giac::context * contextptr = get_context(this);
2367     begin_sel=-1;
2368     end_sel=-1;
2369     // mode is 1 for shifted key
2370     Equation_select_up(data,xcur,ycur,mode);
2371     adjust_xy_sel();
2372     if (cb_select)
2373       cb_select(get_selection().print(contextptr).c_str());
2374     redraw();
2375   }
2376 
2377   // decrease selection up (like HP49 eqw Down key)
Equation_select_down(gen & g,int x,int y,int mode,Equation * eq)2378   void Equation_select_down(gen & g,int x,int y,int mode, Equation * eq){
2379     const giac::context * contextptr = get_context(eq);
2380     if (g.type==_EQW){ // terminal -> deselect and activate
2381       eqwdata & e=*g._EQWptr;
2382       e.selected=false;
2383       if (eq->modifiable){
2384 	e.active=true;
2385 	eq->active_pos=0;
2386 	if (e.g.type==_STRNG )
2387 	  eq->need_active_parse=false;
2388 	else {
2389 	  eq->need_active_parse=true;
2390 	  e.g=string2gen(e.g.print(contextptr),false);
2391 	  e.g.subtype=1;
2392 	}
2393       }
2394       return;
2395     }
2396     if (g.type!=_VECT || g._VECTptr->empty() )
2397       return;
2398     vecteur & v=*g._VECTptr;
2399     iterateur it=v.begin(),itend=v.end()-1;
2400     if (itend->type!=_EQW)
2401       setsizeerr();
2402     eqwdata & w=*itend->_EQWptr;
2403     if (w.selected){ // deselect operator (sommet of the symbolic)
2404       w.selected=false;
2405       if (itend-it==1)
2406 	return;
2407     }
2408     int i,j,nrows,ncols;
2409     if ( mode && w.g==at_makevector && Equation_find_matrix_pos(it,itend,i,j,nrows,ncols) ){
2410       ++i;
2411       if (i>=nrows)
2412 	i=0;
2413       Equation_select(g,false);
2414       Equation_select_matrix_pos(it,i,j);
2415       return;
2416     }
2417     if ( mode && w.g==at_multistring && Equation_find_multistring_pos(it,itend,i,nrows) ){
2418       ++i;
2419       if (i>=nrows)
2420 	i=0;
2421       Equation_select(g,false);
2422       Equation_select_multistring_pos(it,i);
2423       return;
2424     }
2425     // not selected, find the 1st selected element if any
2426     int x0,y0,w0,h0;
2427     attributs attr(0,0,0);
2428     bool selected;
2429     for (;it!=itend;++it){
2430       Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected);
2431       if (selected)
2432 	break;
2433     }
2434     if (selected){ // deselect all elements except this one
2435       iterateur it1=v.begin();
2436       bool des=false;
2437       int tmp;
2438       for (;it1!=itend;++it1){
2439 	if (it1!=it){ // if *it1 was selected deselect it
2440 	  if (Equation_adjust_xy(*it1,tmp,tmp,tmp,tmp)){
2441 	    des=true;
2442 	    Equation_select(*it1,false);
2443 	  }
2444 	}
2445       }
2446       if (!des){ // nothing else was selected, recurse
2447 	Equation_select_down(*it,x,y,mode,eq);
2448       }
2449       return;
2450     }
2451     it=v.begin();
2452     for (;it!=itend;++it){
2453       Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected);
2454       if ( (x0<=x) && (x0+w0>=x) && (y0<=y) && (y0+h0>=y) )
2455 	break;
2456     }
2457     if (it!=itend)
2458       Equation_select_down(*it,x,y,mode,eq);
2459   }
2460 
select_down(int mode)2461   void Equation::select_down(int mode){
2462     const giac::context * contextptr = get_context(this);
2463     begin_sel=-1;
2464     end_sel=-1;
2465     Equation_select_down(data,xcur,ycur,mode,this);
2466     adjust_xy_sel();
2467     if (cb_select)
2468       cb_select(get_selection().print(contextptr).c_str());
2469     redraw();
2470   }
2471 
Equation_data2gen(const gen & g,GIAC_CONTEXT)2472   gen Equation_data2gen(const gen & g,GIAC_CONTEXT){
2473     if (g.type==_EQW){
2474       eqwdata & e=*g._EQWptr;
2475       if ( e.g.type==_STRNG && e.active && e.g.subtype )
2476 	 return gen(*e.g._STRNGptr,contextptr);
2477       return e.g;
2478     }
2479     if (g.type!=_VECT)
2480       return g;
2481     vecteur & v=*g._VECTptr;
2482     const_iterateur it=v.begin(),itend=v.end()-1;
2483     vecteur res;
2484     if (g.subtype==_HIST__VECT){
2485       vecteur tmp(2);
2486       for (;it!=itend;++it){
2487 	tmp[0]=Equation_data2gen(*it,contextptr);
2488 	++it;
2489 	if (it==itend)
2490 	  break;
2491 	tmp[1]=Equation_data2gen(*it,contextptr);
2492 	res.push_back(tmp);
2493       }
2494       return gen(res,_HIST__VECT);
2495     }
2496     res.reserve(itend-it);
2497     for (;it!=itend;++it){
2498       res.push_back(Equation_data2gen(*it,contextptr));
2499     }
2500     gen f=Equation_data2gen(*it,contextptr);
2501     if (f==at_makesuite)
2502       return gen(res,_SEQ__VECT);
2503     if (f==at_makevector){
2504       if (f.subtype==_MATRIX__VECT && ckmatrix(res)){
2505 	iterateur it=res.begin();itend=res.end();
2506 	for (;it!=itend;++it)
2507 	  it->subtype=0;
2508 	return res;
2509       }
2510       return gen(res,f.subtype);
2511     }
2512     if (f==at_program && res.size()==2)
2513       res.insert(res.begin()+1,res.front()*zero);
2514     if (f==at_at && xcas_mode(contextptr)!=0){
2515       if (res.size()==2){
2516 	if (res.back().type==_VECT){
2517 	  vecteur & resv=*res.back()._VECTptr;
2518 	  res.back()=gen(subvecteur(resv,vecteur(resv.size(),plus_one)),_SEQ__VECT);
2519 	}
2520 	else
2521 	  res.back()=res.back()-plus_one;
2522       }
2523     }
2524     gen arg=gen(res,g.subtype);
2525     if (f.type==_FUNC) {
2526       if (res.size()==1)
2527 	return symbolic(*f._FUNCptr,res.front());
2528       else {
2529 	if (f==at_multistring){
2530 	  gen tmp=_multistring(res,contextptr);
2531 	  return tmp;
2532 	}
2533 	return symbolic(*f._FUNCptr,arg);
2534       }
2535     }
2536     else
2537       return f(arg,contextptr);
2538   }
2539 
Equation_selected2gen(Equation * eq,const gen & g,bool & selected,bool search_active=false)2540   gen Equation_selected2gen(Equation * eq,const gen & g,bool & selected,bool search_active=false){
2541     const giac::context * contextptr = get_context(eq);
2542     if (g.type==_EQW){
2543       eqwdata & e=*g._EQWptr;
2544       if (search_active)
2545 	selected = e.active;
2546       else
2547 	selected = e.selected;
2548       if (!selected)
2549 	return Equation_nullstring();
2550       if (e.g.type!=_STRNG)
2551 	return e.g;
2552       if (e.active && e.g.subtype )
2553 	return gen(*e.g._STRNGptr,contextptr); // parse
2554       // begin_sel/end_sel
2555       string res=*e.g._STRNGptr;
2556       if (!e.active)
2557 	res=Equation_extract_string(*e.g._STRNGptr,eq->begin_sel,eq->end_sel);
2558       return string2gen(res,false);
2559     }
2560     selected=false;
2561     if (g.type!=_VECT)
2562       return g;
2563     vecteur & v=*g._VECTptr;
2564     const_iterateur it=v.begin(),itend=v.end()-1;
2565     if (itend->type==_EQW && itend->_EQWptr->g==at_multistring){
2566       string res;
2567       if (!Equation_multistring_selection(it,itend,search_active))
2568 	return string2gen(res,false);
2569       selected=true;
2570       if (it==itend) // selection inside one string
2571 	return Equation_selected2gen(eq,*it,selected,search_active);
2572       res=Equation_extract_string(*it->_EQWptr->g._STRNGptr,eq->begin_sel,-1)+'\n';
2573       ++it;
2574       for (;it!=itend;++it)
2575 	res=res+*it->_EQWptr->g._STRNGptr+'\n';
2576       res=res+Equation_extract_string(*itend->_EQWptr->g._STRNGptr,-1,eq->end_sel);
2577       return string2gen(res,false);
2578     }
2579     int w0,h0,x0,y0;
2580     attributs attr(0,0,0);
2581     Equation_box_sizes(*itend,w0,h0,x0,y0,attr,selected,search_active);
2582     if (selected)
2583       return Equation_data2gen(g,contextptr);
2584     vecteur res;
2585     res.reserve(itend-it);
2586     for (;it!=itend;++it){
2587       gen tmp=Equation_selected2gen(eq,*it,selected,search_active);
2588       if (selected)
2589 	res.push_back(tmp);
2590     }
2591     selected=!res.empty();
2592     if (!selected)
2593       return zero;
2594     if (res.size()==1)
2595       return res.front();
2596     gen f=Equation_data2gen(*it,contextptr);
2597     if (f==at_makesuite)
2598       return gen(res,_SEQ__VECT);
2599     if (f==at_makevector){
2600       if (f.subtype==_MATRIX__VECT && ckmatrix(res)){
2601 	iterateur it=res.begin();itend=res.end();
2602 	for (;it!=itend;++it)
2603 	  it->subtype=0;
2604 	return res;
2605       }
2606       return gen(res,f.subtype);
2607     }
2608     if (f==at_program && res.size()==2)
2609       res.insert(res.begin()+1,res.front()*zero);
2610     if (f==at_at && xcas_mode(contextptr)!=0){
2611       if (res.size()==2){
2612 	if (res.back().type==_VECT){
2613 	  vecteur & resv=*res.back()._VECTptr;
2614 	  res.back()=gen(subvecteur(resv,vecteur(resv.size(),plus_one)),_SEQ__VECT);
2615 	}
2616 	else
2617 	  res.back()=res.back()-plus_one;
2618       }
2619     }
2620     gen arg=gen(res,g.subtype);
2621     if (f.type==_FUNC)
2622       return symbolic(*f._FUNCptr,arg);
2623     else
2624       return f(arg,contextptr);
2625   }
2626 
2627   // return a pointer to the selected object
2628   // it will modify g if for example a subsum of a sum is selected
Equation_selected(gen & g,attributs & attr,int windowhsize,vecteur & position,bool active_search,GIAC_CONTEXT)2629   gen * Equation_selected(gen & g,attributs & attr,int windowhsize,vecteur & position,bool active_search,GIAC_CONTEXT){
2630     // FIXME begin_sel/end_sel
2631     int x0,y0,w0,h0,tmp;
2632     bool selected;
2633     if (!Equation_adjust_xy(g,tmp,tmp,tmp,tmp,active_search))
2634       return 0;
2635     Equation_box_sizes(g,w0,h0,x0,y0,attr,selected,active_search);
2636     if (selected)
2637       return &g;
2638     if (g.type!=_VECT)
2639       return 0;
2640     vecteur & v=*g._VECTptr;
2641     iterateur it=v.begin(),itend=v.end()-1;
2642     for (;it!=itend;++it){ // search first selected item
2643       Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected,active_search);
2644       if (selected)
2645 	break;
2646     }
2647     if (it==itend){
2648       it=v.begin();
2649       for (;it!=itend;++it){
2650 	if (Equation_adjust_xy(*it,tmp,tmp,tmp,tmp,active_search)){
2651 	  position.push_back(int(it-v.begin()));
2652 	  return Equation_selected(*it,attr,windowhsize,position,active_search,contextptr);
2653 	}
2654       }
2655       return 0;
2656     }
2657     iterateur itb=it;
2658     position.push_back(int(it-v.begin()));
2659     // find the end of the selection
2660     ++it;
2661     for (;it!=itend;++it){
2662       Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected,active_search);
2663       if (!selected)
2664 	break;
2665     }
2666     --it;
2667     Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected,active_search);
2668     if (it==itb)
2669       return &*it;
2670     // arrange v
2671     if (itb==v.begin() && it+1==itend){
2672       position.pop_back();
2673       return &g;
2674     }
2675     vecteur subop(itb,it+1);
2676     subop.push_back(v.back());
2677     gen temp=Equation_data2gen(subop,contextptr);
2678     eqwdata e=Equation_total_size(*it);
2679     *it=Equation_compute_size(temp,attr,windowhsize,contextptr);
2680     Equation_translate(*it,e.x,e.y);
2681     int pos=itb-v.begin();
2682     v.erase(itb,it);
2683     return &v[pos];
2684   }
2685 
2686   // make a free copy of g
Equation_copy(const gen & g)2687   gen Equation_copy(const gen & g){
2688     if (g.type==_EQW)
2689       return *g._EQWptr;
2690     if (g.type!=_VECT)
2691       return g;
2692     vecteur & v = *g._VECTptr;
2693     const_iterateur it=v.begin(),itend=v.end();
2694     vecteur res;
2695     res.reserve(itend-it);
2696     for (;it!=itend;++it)
2697       res.push_back(Equation_copy(*it));
2698     return gen(res,g.subtype);
2699   }
2700 
2701   // move selection right (like HP49 eqw Right key)
Equation_select_rightleft(gen & g,Equation * eqptr,int windowhsize,bool right,int mode,GIAC_CONTEXT)2702   void Equation_select_rightleft(gen & g,Equation * eqptr,int windowhsize,bool right,int mode,GIAC_CONTEXT){
2703     if (g.type!=_VECT)  // we are on a terminal, nothing to do
2704       return;
2705     // find 1st object with something selected
2706     vecteur & v=*g._VECTptr;
2707     iterateur it=v.begin(),itend=v.end()-1;
2708     eqwdata & w=*itend->_EQWptr;
2709     int i,j,nrows,ncols,tmp;
2710     if ( (mode) && (w.g==at_makevector) && Equation_find_matrix_pos(it,itend,i,j,nrows,ncols) ){
2711       if (right)
2712 	++j;
2713       else
2714 	--j;
2715       if (j<0)
2716 	j=ncols-1;
2717       if (j>=ncols)
2718 	j=0;
2719       Equation_select(g,false);
2720       Equation_select_matrix_pos(it,i,j);
2721       return;
2722     }
2723     for (;it!=itend;++it){
2724       if (Equation_adjust_xy(*it,tmp,tmp,tmp,tmp))
2725 	break;
2726     }
2727     if (it==itend)
2728       return;
2729     iterateur it0=it; // save first selected
2730     // find first non selected
2731     if (right || (mode==2) ){
2732       ++it;
2733       for (;it!=itend;++it){
2734 	if (!Equation_adjust_xy(*it,tmp,tmp,tmp,tmp))
2735 	  break;
2736       }
2737       if (mode==2 && it0==v.begin() && it==itend)
2738 	return;
2739       --it;
2740     }
2741     // it -> last selected if moving right or exchanging selection right/left
2742     int x0,y0,w0,h0;
2743     attributs attr(0,0,0);
2744     bool selected;
2745     Equation_box_sizes(*it,w0,h0,x0,y0,attr,selected);
2746     if (!selected){
2747       Equation_select_rightleft(*it,eqptr,windowhsize,right,mode,contextptr);
2748       return;
2749     }
2750     iterateur it1=it;
2751     if (right){
2752       ++it;
2753       if (it==itend)
2754 	it=v.begin();
2755     }
2756     else {
2757       it=it0;
2758       if (it==v.begin())
2759 	it=itend;
2760       --it;
2761     }
2762     if (mode==2){ // exchange it0->it1 with it
2763       if (it1==it0){
2764 	gen tmp=*it;
2765 	*it=*it0;
2766 	*it0=tmp;
2767       }
2768       else {
2769 	vecteur tmpv(it0,it1+1);
2770 	tmpv.push_back(*itend);
2771 	gen sel=Equation_data2gen(tmpv,contextptr);
2772 	sel=Equation_compute_size(sel,attr,windowhsize,contextptr);
2773 	Equation_select(sel,true);
2774 	gen tmp=*it;
2775 	*it=sel;
2776 	*it1=tmp;
2777 	v.erase(it0,it1);
2778       }
2779       vecteur position;
2780       gen g_copy=Equation_copy(eqptr->data);
2781       gen * ptr=Equation_selected(eqptr->data,attr,windowhsize,position,false,contextptr);
2782       if (ptr){
2783 	if (ptr->type==_VECT && !ptr->_VECTptr->empty() && ptr->_VECTptr->back().type==_EQW && ptr->_VECTptr->back()._EQWptr->g==at_multistring){
2784 	  eqptr->data=g_copy;
2785 	  return;
2786 	}
2787 	const gen & tmp=Equation_data2gen(eqptr->data,contextptr);
2788 	eqptr->data=Equation_compute_size(tmp,attr,windowhsize,contextptr);
2789 	const_iterateur it=position.begin(),itend=position.end();
2790 	ptr=&eqptr->data;
2791 	for (;it!=itend;++it){
2792 	  ptr=&(*ptr->_VECTptr)[it->val];
2793 	}
2794 	Equation_select(*ptr,true);
2795       }
2796       return;
2797     }
2798     else {
2799       // if shift-arrow, extend selection, mode==0 do not deselect
2800       if (mode==1)
2801 	Equation_select(g,false);
2802     }
2803     Equation_select(*it,true);
2804   }
2805 
select_right(int mode)2806   void Equation::select_right(int mode){
2807     begin_sel=-1;
2808     end_sel=-1;
2809     const giac::context * contextptr = get_context(this);
2810     Equation_select_rightleft(data,this,w(),true,mode,contextptr);
2811     adjust_xy_sel();
2812     if (cb_select)
2813       cb_select(get_selection().print(contextptr).c_str());
2814     redraw();
2815   }
2816 
select_left(int mode)2817   void Equation::select_left(int mode){
2818     begin_sel=-1;
2819     end_sel=-1;
2820     const giac::context * contextptr = get_context(this);
2821     Equation_select_rightleft(data,this,w(),false,mode,contextptr);
2822     adjust_xy_sel();
2823     if (cb_select)
2824       cb_select(get_selection().print(contextptr).c_str());
2825     redraw();
2826   }
2827 
2828   /* // modify g in place
2829   void Equation_eval_function(const gen & f,gen & g,attributs iattr,int windowhsize){
2830 
2831     attributs attr(0,0,0);
2832     vecteur position;
2833     gen g_copy=Equation_copy(g);
2834     gen * ptr=Equation_selected(g,attr,windowhsize,position,contextptr);
2835     if (!ptr) // should begin entry mode here
2836       return;
2837     if (ptr->type==_VECT && !ptr->_VECTptr->empty() && ptr->_VECTptr->back().type==_EQW && ptr->_VECTptr->back()._EQWptr->g==at_multistring){
2838       g=g_copy;
2839       return;
2840     }
2841     gen tmp=Equation_data2gen(*ptr,contextptr);
2842     tmp=f(eval(tmp));
2843     * ptr = Equation_compute_size(tmp,attr,windowhsize,contextptr);
2844     tmp=Equation_data2gen(g,contextptr);
2845     g=Equation_compute_size(tmp,iattr,windowhsize,contextptr);
2846     const_iterateur it=position.begin(),itend=position.end();
2847     ptr=&g;
2848     for (;it!=itend;++it){
2849       ptr=&(*ptr->_VECTptr)[it->val];
2850     }
2851     Equation_select(*ptr,true);
2852   }
2853   */
2854 
save_data()2855   void Equation::save_data(){
2856     int us=undo_history.size();
2857     if (undo_history_pos>=int(us)){
2858       undo_history.push_back(get_data());
2859     }
2860     else {
2861       undo_history[undo_history_pos]=get_data();
2862       iterateur it=undo_history.begin()+undo_history_pos+1;
2863       undo_history.erase(it,undo_history.end());
2864     }
2865     us=undo_history.size();
2866     undo_history_pos=us;
2867     if (us>1){ // check that the last 2 levels are not identical
2868       if (undo_history[us-2]==undo_history[us-1]){
2869 	undo_history.pop_back();
2870 	--undo_history_pos;
2871       }
2872     }
2873   }
2874 
rcl_data(int dpos)2875   void Equation::rcl_data(int dpos){
2876     int us=undo_history.size();
2877     if (!us)
2878       return;
2879     if (undo_history_pos>=us)
2880       undo_history_pos=us-1;
2881     undo_history_pos += dpos ;
2882     if (undo_history_pos>=us)
2883       undo_history_pos=us-1;
2884     if (undo_history_pos<0)
2885       undo_history_pos=0;
2886     set_data(undo_history[undo_history_pos]);
2887     select();
2888     // adjust_xy_sel();
2889     // redraw();
2890   }
2891 
eval_function(const gen & f)2892   void Equation::eval_function(const gen & f){
2893     save_data();
2894     gen fx=symbolic(at_of,makevecteur(f,get_selection()));
2895     replace_selection_wo_save(fx);
2896     save_data();
2897     xcas::History_Pack * hp=get_history_pack(this);
2898     giac::context * cptr=hp?hp->contextptr:0;
2899     //bool ok=
2900     make_thread(fx,eval_level(cptr),Equation_eval_callback,this,cptr);
2901   }
2902 
get_selection()2903   gen Equation::get_selection(){
2904     bool has_selection;
2905     return Equation_selected2gen(this,data,has_selection);
2906   }
2907 
get_data() const2908   gen Equation::get_data() const{
2909     const giac::context * contextptr = get_context(this);
2910     return Equation_data2gen(data,contextptr);
2911   }
2912 
value() const2913   string Equation::value() const{
2914     const giac::context * contextptr = get_context(this);
2915     return Equation_data2gen(data,contextptr).print(contextptr);
2916   }
2917 
set_data(const gen & g)2918   void Equation::set_data(const gen & g){
2919     const giac::context * contextptr = get_context(this);
2920     data=Equation_compute_size(g,attr,w(),contextptr);
2921     eqwdata e = Equation_total_size(data);
2922     // FIXME? ytop = e.y;
2923     ytop=h();
2924     // FIXME? xleft = e.x;
2925     xleft=0;
2926     setscroll();
2927   }
2928 
Equation_replace_selection(const gen & f,Equation * eqwptr,int windowhsize,bool active_search=false)2929   bool Equation_replace_selection(const gen & f,Equation * eqwptr,int windowhsize,bool active_search=false){
2930     const giac::context * contextptr = get_context(eqwptr);
2931     eqwptr->redraw();
2932     gen & g = eqwptr->data;
2933     attributs attr(0,0,0);
2934     vecteur position;
2935     gen save_g=Equation_copy(g);
2936     gen * ptr=Equation_selected(g,attr,windowhsize,position,active_search,contextptr);
2937     if (!ptr) {
2938       g=save_g;
2939       return false;
2940     }
2941     if (g.type==_VECT && g.subtype==_HIST__VECT && !position.empty()){
2942       if ( (position.front().val%2) ^ rpn_mode(contextptr)){
2943 	g=save_g;
2944 	return false;
2945       }
2946     }
2947     bool stringrep= !active_search && ptr->type==_EQW && ptr->_EQWptr->g.type==_STRNG && eqwptr->begin_sel>=0 && eqwptr->end_sel>=0 ;
2948     bool multistringrep= ptr->type==_VECT && !ptr->_VECTptr->empty() && ptr->_VECTptr->back().type==_EQW && ptr->_VECTptr->back()._EQWptr->g==at_multistring;
2949     if (multistringrep){ // check if the whole multistring is replaced or not
2950       *ptr=Equation_nullstring(eqwptr->attr,0,contextptr);
2951       multistringrep= in_multistring(eqwptr->data)!=-1;
2952     }
2953     if (stringrep || multistringrep){
2954       g=save_g;
2955       eqwptr->remove_selection();
2956       vecteur position;
2957       gen * act=Equation_selected(eqwptr->data,eqwptr->attr,eqwptr->w(),position,1,contextptr);
2958       string s;
2959       if (f.type==_STRNG)
2960 	s=*f._STRNGptr;
2961       else
2962 	s=f.print(contextptr);
2963       eqwptr->handle_text(s,act);
2964       return true;
2965     }
2966     if (g.type==_VECT && g.subtype==_HIST__VECT && position.size()>=1 && position.size()<=2){
2967       int pos=position.front().val;
2968       bool doit=pos>=0 && pos<int(g._VECTptr->size());
2969       if (doit){
2970 	if (position.size()==2){
2971 	  doit=false;
2972 	  if (is_zero(position.back())){
2973 	    gen gtmp=g[pos];
2974 	    if (gtmp.type==_VECT && gtmp._VECTptr->back().type==_EQW && gtmp._VECTptr->back()._EQWptr->g==at_expr)
2975 	      doit=true;
2976 	  }
2977 	}
2978       }
2979       if (doit){
2980 	g = save_g;
2981 	Equation_select(g,false,active_search);
2982 	vecteur & v = *g._VECTptr;
2983 	int s=v.size(),newdx;
2984 	eqwdata olde=Equation_total_size(v[pos]);
2985 	if (position.size()==2){
2986 	  gen vposfront=Equation_data2gen(v[pos],contextptr);
2987 	  gen vposfrontf=vposfront._SYMBptr->feuille;
2988 	  if (vposfrontf.type==_VECT && !vposfrontf._VECTptr->empty()){
2989 	    vecteur vposfrontv=*vposfrontf._VECTptr;
2990 	    vposfrontv[0]=f;
2991 	    vposfrontf=gen(vposfrontv,vposfrontf.subtype);
2992 	  }
2993 	  else
2994 	    vposfrontf=f;
2995 	  v[pos]=Equation_compute_size(symbolic(at_expr,vposfrontf),olde.eqw_attributs,windowhsize,contextptr);
2996 	}
2997 	else {
2998 	  v[pos]=Equation_compute_size(f,olde.eqw_attributs,windowhsize,contextptr);
2999 	}
3000 	eqwdata newe=Equation_total_size(v[pos]);
3001 	int deltady=newe.dy-olde.dy;
3002 	if (pos%2){
3003 	  int xshift=int(fl_width("    "));;
3004 	  if (newe.dx+4<windowhsize-eqwptr->attr.fontsize){
3005 	    if (center_history)
3006 	      xshift=(windowhsize-newe.dx-4)/2;
3007 	    else
3008 	      xshift=windowhsize-newe.dx-4-eqwptr->attr.fontsize;
3009 	  }
3010 	  newdx=newe.dx+xshift;
3011 	  Equation_translate(v[pos],xshift-newe.x,olde.y-newe.y-deltady);
3012 	}
3013 	else {
3014 	  newdx=newe.dx+olde.x;
3015 	  Equation_translate(v[pos],olde.x-newe.x,olde.y-newe.y-deltady);
3016 	}
3017 	if (position.size()==2)
3018 	  Equation_select(v[pos]._VECTptr->front(),true,active_search);
3019 	else
3020 	  Equation_select(v[pos],true,active_search);
3021 	// translate the rest of history
3022 	for (++pos;pos<s;++pos){
3023 	  Equation_translate(v[pos],0,-deltady);
3024 	}
3025 	--pos;
3026 	if (v[pos].type==_EQW){ // should be true!
3027 	  eqwdata & e = *v[pos]._EQWptr;
3028 	  e.dx=max(e.dx,newdx);
3029 	  eqwptr->xleft=e.dx;
3030 	}
3031 	eqwptr->setscroll();
3032 	return true;
3033       }
3034     }
3035     eqwdata olde=Equation_total_size(*ptr);
3036     *ptr=Equation_compute_size(f,olde.eqw_attributs,windowhsize,contextptr);
3037     gen tmp=Equation_data2gen(g,contextptr);
3038     g=Equation_compute_size(tmp,eqwptr->attr,windowhsize,contextptr);
3039     const_iterateur it=position.begin(),itend=position.end();
3040     ptr=&g;
3041     for (;it!=itend;++it){
3042       ptr=&(*ptr->_VECTptr)[it->val];
3043     }
3044     Equation_select(*ptr,true,active_search);
3045     return true;
3046   }
3047 
replace_selection(const gen & f,bool active_search)3048   bool Equation::replace_selection(const gen & f,bool active_search){
3049     save_data();
3050     return replace_selection_wo_save(f,active_search);
3051   }
3052 
adjust_widget_size()3053   void Equation::adjust_widget_size(){
3054     // recompute widget size
3055     eqwdata e=Equation_total_size(data);
3056     int maxh=window()?(window()->h())/3:1000;
3057     int scrollsize=3;
3058     if (e.dx>w()-2*labelsize())
3059       scrollsize=labelsize()+3;
3060     int newh=min(e.dy+scrollsize+1,maxh); // =max(min(vv.dy+20,400),60);
3061     increase_size(this,newh-h());
3062     int largeur=labelsize();
3063     vscroll->resize(x()+Fl_Group::w()-largeur,y(),largeur,Fl_Group::h()-labelsize());
3064     hscroll->resize(x(),y()+Fl_Group::h()-labelsize(),Fl_Group::w()-2*largeur,labelsize());
3065     menubar->resize(hscroll->x()+hscroll->w(),hscroll->y(),this->w()-hscroll->w(),hscroll->h());
3066   }
3067 
replace_selection_wo_save(const gen & f,bool active_search)3068   bool Equation::replace_selection_wo_save(const gen & f,bool active_search){
3069     bool res=Equation_replace_selection(f,this,w(),active_search);
3070     if (res)
3071       save_data();
3072     // recompute widget size
3073     adjust_widget_size();
3074     if (!active_search)
3075       fl_select();
3076     adjust_xy_sel();
3077     redraw();
3078     return res;
3079   }
3080 
3081   // deselect and activate
Equation_deselect_and_activate(gen & g)3082   bool Equation_deselect_and_activate(gen & g){
3083     if (g.type==_EQW){
3084       if (g._EQWptr->selected){
3085 	g._EQWptr->selected=false;
3086 	g._EQWptr->active=true;
3087 	return true;
3088       }
3089       else
3090 	return false;
3091     }
3092     if (g.type!=_VECT)
3093       return false;
3094     vecteur & v = *g._VECTptr;
3095     iterateur it=v.begin(),itend=v.end()-1;
3096     if (Equation_deselect_and_activate(*itend))
3097       return true;
3098     for (;it!=itend;++it){
3099       if (Equation_deselect_and_activate(*it))
3100 	return true;
3101     }
3102     return false;
3103   }
3104 
deselect_and_activate()3105   void Equation::deselect_and_activate(){
3106     begin_sel=-1;
3107     end_sel=-1;
3108     active_pos=0;
3109     Equation_deselect_and_activate(data);
3110   }
3111 
Equation_desactivate_and_select(gen & g,bool need_active_parse)3112   bool Equation_desactivate_and_select(gen & g,bool need_active_parse){
3113     if (g.type==_EQW){
3114       if (g._EQWptr->active){
3115 	g._EQWptr->active=false;
3116 	g._EQWptr->selected=true;
3117 	if (need_active_parse && g._EQWptr->g.type==_STRNG )
3118 	  g._EQWptr->g=gen(*g._EQWptr->g._STRNGptr,context0);
3119 	return true;
3120       }
3121       else
3122 	return false;
3123     }
3124     if (g.type!=_VECT)
3125       return false;
3126     vecteur & v = *g._VECTptr;
3127     iterateur it=v.begin(),itend=v.end()-1;
3128     if (Equation_desactivate_and_select(*itend,need_active_parse))
3129       return true;
3130     for (;it!=itend;++it){
3131       if (Equation_desactivate_and_select(*it,need_active_parse))
3132 	return true;
3133     }
3134     return false;
3135   }
3136 
desactivate_and_select()3137   void Equation::desactivate_and_select(){
3138     begin_sel=-1;
3139     end_sel=-1;
3140     Equation_desactivate_and_select(data,need_active_parse);
3141   }
3142 
3143   // if nothing selected, select active -> select something
3144   // Parse selection
insure_something_selected(bool selectall)3145   void Equation::insure_something_selected(bool selectall){
3146     bool has_selection=false;
3147     gen g=Equation_selected2gen(this,data,has_selection);
3148     if (!has_selection){
3149       if (selectall)
3150 	select();
3151       else {
3152 	// Check for something active, desactive and select
3153 	g=Equation_selected2gen(this,data,has_selection,1);
3154 	if (has_selection){
3155 	  desactivate_and_select();
3156 	}
3157 	else {
3158 	  select_up(0);
3159 	  g=Equation_selected2gen(this,data,has_selection);
3160 	}
3161       }
3162     }
3163   }
3164 
Equation_parse_desactivate(gen & g,Equation * eq)3165   bool Equation_parse_desactivate(gen & g,Equation * eq){
3166     const giac::context * contextptr = get_context(eq);
3167     if (g.type==_EQW){
3168       eqwdata & e=*g._EQWptr;
3169       if (!e.active)
3170 	return false;
3171       e.active=false;
3172       e.selected=true;
3173       if (e.g.type==_STRNG && eq->need_active_parse){
3174 	try {
3175 	  gen g1=gen(*e.g._STRNGptr,contextptr);
3176 	  e.g=g1;
3177 	  eq->replace_selection(g1);
3178 	}
3179 	catch (std::runtime_error & er){
3180 	  cerr << er.what() << '\n';
3181 	}
3182       }
3183       return true;
3184     }
3185     if (g.type!=_VECT)
3186       return false;
3187     vecteur & v =*g._VECTptr;
3188     iterateur it=v.begin(),itend=v.end();
3189     for (;it!=itend;++it){
3190       if (Equation_parse_desactivate(*it,eq))
3191 	return true;
3192     }
3193     return false;
3194   }
3195 
parse_desactivate()3196   bool Equation::parse_desactivate(){
3197     begin_sel=-1;
3198     end_sel=-1;
3199     if (!Equation_parse_desactivate(data,this))
3200       return false;
3201     return true;
3202   }
3203 
3204   // return true if something selected inside or whole selected
Equation_is_selected(const gen & g,bool inside=false,bool active_search=false)3205   bool Equation_is_selected(const gen & g,bool inside=false,bool active_search=false){
3206     if (g.type==_EQW){
3207       if (active_search)
3208 	return g._EQWptr->active;
3209       else
3210 	return g._EQWptr->selected;
3211     }
3212     if (g.type!=_VECT || g._VECTptr->empty())
3213       return false;
3214     if (Equation_is_selected(g._VECTptr->back(),inside,active_search))
3215       return true;
3216     if (!inside)
3217       return false;
3218     const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
3219     for (;it!=itend;++it){
3220       if (Equation_is_selected(*it,inside,active_search))
3221 	return true;
3222     }
3223     return false;
3224   }
3225 
is_selected(bool inside,bool active_search)3226   bool Equation::is_selected(bool inside,bool active_search){
3227     return Equation_is_selected(data,inside,active_search);
3228   }
3229 
Equation_nullstring()3230   gen Equation_nullstring(){
3231     gen tmps=string2gen("",false);
3232     tmps.subtype=1;
3233     return tmps;
3234   }
3235 
Equation_nullhistlevel()3236   gen Equation_nullhistlevel(){
3237     gen hh1,hh2(string2gen("",false));
3238     hh1=Equation_nullstring();
3239     gen hh=gen(vecteur(1,makevecteur(hh1,hh2)),_HIST__VECT);
3240     return hh;
3241   }
3242 
is_semi_expr(const gen & g)3243   bool is_semi_expr(const gen & g){
3244     if (!g.is_symb_of_sommet(at_expr))
3245       return false;
3246     gen tmp=g._SYMBptr->feuille;
3247     return tmp.type==_VECT && tmp.subtype==_SEQ__VECT && tmp._VECTptr->front().type==_STRNG && *tmp._VECTptr->front()._STRNGptr==";";
3248   }
3249 
Equation_nullstring(const attributs & a,int windowhsize,GIAC_CONTEXT)3250   gen Equation_nullstring(const attributs & a,int windowhsize,GIAC_CONTEXT){
3251     gen g=Equation_compute_size(Equation_nullstring(),a,windowhsize,contextptr);
3252     Equation_select(g,true,1);
3253     return g;
3254   }
3255 
Equation_remove_selection(gen & g,int & pos,Equation * eq)3256   void Equation_remove_selection(gen & g,int & pos,Equation * eq){
3257     const giac::context * contextptr = get_context(eq);
3258     if (g.type==_EQW){
3259       eqwdata & e=*g._EQWptr;
3260       if (e.g.type==_STRNG){
3261 	eq->need_active_parse=false;
3262 	string s = *e.g._STRNGptr;
3263 	int ss=s.size();
3264 	if (ss){
3265 	  int begin_sel=max(0,min(eq->begin_sel,ss-1));
3266 	  int end_sel=ss;
3267 	  if (eq->end_sel>=0)
3268 	    end_sel=min(eq->end_sel,ss);
3269 	  if (end_sel<begin_sel)
3270 	    giac::swapint(begin_sel,end_sel);
3271 	  if (end_sel<ss)
3272 	    s = s.substr(0,begin_sel)+s.substr(end_sel,ss-end_sel);
3273 	  else
3274 	    s = s.substr(0,begin_sel);
3275 	  pos = begin_sel;
3276 	}
3277 	else
3278 	  pos=0;
3279 	e.g = string2gen(s,false);
3280       }
3281       else {
3282 	eq->need_active_parse=true;
3283 	e.g=string2gen(e.g.print(contextptr),false);
3284 	e.g.subtype=1;
3285 	pos=e.g._STRNGptr->size();
3286       }
3287       e.active=true;
3288       e.selected=false;
3289       return;
3290     }
3291     if (g.type!=_VECT)
3292       return;
3293     vecteur & v =*g._VECTptr;
3294     iterateur it=v.begin(),itend=v.end();
3295     if (Equation_is_selected(*(itend-1),false)){
3296       g=Equation_nullstring(v.back()._EQWptr->eqw_attributs,0,contextptr);
3297       pos=0;
3298       return;
3299     }
3300     for (;it!=itend;++it){
3301       if (Equation_is_selected(*it,false))
3302 	break;
3303     }
3304     if (it!=itend){
3305       iterateur it0=it;
3306       int pos=it0-v.begin();
3307       for (;it!=itend;++it){
3308 	if (!Equation_is_selected(*it,false))
3309 	  break;
3310       }
3311       if (v.back().type == _EQW && v.back()._EQWptr->g==at_multistring && it0->type==_EQW && it0->_EQWptr->g.type==_STRNG && eq->begin_sel>=0 && eq->end_sel>=0){
3312 	--it; // it0 first selected, it last selected
3313 	int ss=it->_EQWptr->g._STRNGptr->size();
3314 	int begin_sel=min(eq->begin_sel,ss),end_sel=min(eq->end_sel,ss);
3315 	Equation_select(*it0,false);
3316 	if (it==it0){
3317 	  *it->_EQWptr->g._STRNGptr=it->_EQWptr->g._STRNGptr->substr(0,begin_sel)+it->_EQWptr->g._STRNGptr->substr(end_sel,ss-end_sel);
3318 	  Equation_select(*it,true,true);
3319 	  eq->active_pos=begin_sel;
3320 	  eq->need_active_parse=false;
3321 	  return ;
3322 	}
3323 	begin_sel=giacmin(eq->begin_sel,it0->_EQWptr->g._STRNGptr->size());
3324 	*it0->_EQWptr->g._STRNGptr=it0->_EQWptr->g._STRNGptr->substr(0,begin_sel)+it->_EQWptr->g._STRNGptr->substr(end_sel,ss-end_sel);
3325 	Equation_select(*it0,true,true);
3326 	eq->active_pos=begin_sel;
3327 	eq->need_active_parse=false;
3328 	++it0;
3329 	++it;
3330 	iterateur it1=it0;
3331 	int deltay=0;
3332 	int n=it0-v.begin();
3333 	for (;it1!=it;++it1){
3334 	  eqwdata e=Equation_total_size(*it1);
3335 	  deltay=deltay+e.dy;
3336 	}
3337 	v.erase(it0,it);
3338 	int s=v.size();
3339 	for (int j=n;j<s;++j){
3340 	  Equation_translate(v[j],0,deltay);
3341 	}
3342 	return;
3343       }
3344       // Check whether it0 is a string, in that case erase in the string
3345       if (it0+1==it && it0->type==_EQW && it0->_EQWptr->g.type==_STRNG){
3346 	int ss=it0->_EQWptr->g._STRNGptr->size();
3347 	int begin_sel=max(min(eq->begin_sel,ss),0),end_sel=max(min(eq->end_sel,ss),0);
3348 	Equation_select(*it0,false);
3349 	*it0->_EQWptr->g._STRNGptr=it0->_EQWptr->g._STRNGptr->substr(0,begin_sel)+it0->_EQWptr->g._STRNGptr->substr(end_sel,ss-end_sel);
3350 	Equation_select(*it0,true,true);
3351 	eq->active_pos=begin_sel;
3352 	eq->need_active_parse=false;
3353 	return ;
3354       }
3355       // delete from it0 to it
3356       // NOTE that for history, it must be of even size
3357       if (g.subtype==_HIST__VECT){
3358 	if ( (it0-v.begin())%2)
3359 	  --it0;
3360 	if ( (it-v.begin())%2)
3361 	  ++it;
3362       }
3363       v.erase(it0,it);
3364       if (v.size()==1){ // only the last item, i.e. operator
3365 	g=Equation_nullstring(v.back()._EQWptr->eqw_attributs,0,contextptr);
3366 	pos=0;
3367 	return;
3368       }
3369       if (v.size()==2
3370 	  // && (v.back()._EQWptr->g==at_plus || v.back()._EQWptr->g==at_prod)
3371 	  ){
3372 	g=v.front();
3373 	Equation_select(g,true);
3374 	return;
3375       }
3376       /* it=v.begin(),itend=v.end();
3377 	 for (;it!=itend;++it)
3378 	 Equation_select(*it,true); */
3379       if (pos>1 && pos<int(v.size()))
3380 	Equation_select(v[pos-1],true);
3381       return;
3382     }
3383     // Remove 1st selection
3384     it=v.begin();
3385     for (;it!=itend;++it){
3386       if (Equation_is_selected(*it,true)){
3387 	Equation_remove_selection(*it,pos,eq);
3388 	return;
3389       }
3390     }
3391   }
3392 
remove_selection()3393   void Equation::remove_selection(){
3394     save_data();
3395     Equation_remove_selection(data,active_pos,this);
3396     begin_sel=-1;
3397     end_sel=-1;
3398     redraw();
3399   }
3400 
replace_down_left_activate(const gen & g)3401   void Equation::replace_down_left_activate(const gen & g){
3402     if (replace_selection(g)){
3403       select_down(0);
3404       select_left(0);
3405       deselect_and_activate();
3406       if (in_multistring(data)==-1)
3407 	need_active_parse=true;
3408     }
3409   }
3410 
handle_backspace(Equation * eqwptr,int pos,vecteur * vptr)3411   void handle_backspace(Equation * eqwptr,int pos,vecteur * vptr){
3412     string s=*(*vptr)[pos]._EQWptr->g._STRNGptr;
3413     iterateur it=vptr->begin()+pos;
3414     vptr->erase(it);
3415     --pos;
3416     string s0=*(*vptr)[pos]._EQWptr->g._STRNGptr;
3417     eqwptr->active_pos=s0.size();
3418     s=s0+s;
3419     Equation_select((*vptr)[pos],true,true);
3420     eqwptr->replace_selection(string2gen(s,false),1);
3421   }
3422 
3423   // act = 0 if nothing active or -> the active part
3424   // return true if the new selected part must be copied in clipboard
handle_key(unsigned char c,gen * act)3425   bool Equation::handle_key(unsigned char c,gen * act){
3426     const giac::context * contextptr = get_context(this);
3427     if (!c || c>=0x80)
3428       return false;
3429     if (!act || need_active_parse){
3430       if (c=='(' || c==')'){ // if selection replace vector by sequences
3431 	if (!act){
3432 	  insure_something_selected();
3433 	  gen g=get_selection();
3434 	  if (g.is_symb_of_sommet(at_makevector))
3435 	    replace_selection(symbolic(at_makesuite,g._SYMBptr->feuille));
3436 	  else {
3437 	    if (g.type==_VECT && g.subtype!=_SEQ__VECT){
3438 	      g.subtype=_SEQ__VECT;
3439 	      replace_selection(g);
3440 	    }
3441 	    else
3442 	      replace_selection(symbolic(at_of,makevecteur(f__IDNT_e,g)));
3443 	  }
3444 	  return true;
3445 	}
3446       }
3447       if (c=='[' || c==']'){ // if selection replace seq by vector
3448 	if (!act){
3449 	  insure_something_selected();
3450 	  gen g=get_selection();
3451 	  if (g.is_symb_of_sommet(at_makesuite))
3452 	    replace_selection(symbolic(at_makevector,g._SYMBptr->feuille));
3453 	  else {
3454 	    if (g.type==_VECT && g.subtype==_SEQ__VECT){
3455 	      g.subtype=0;
3456 	      replace_selection(g);
3457 	    }
3458 	    else {
3459 	      g.subtype=_SEQ__VECT;
3460 	      replace_selection(symbolic(at_at,makevecteur(m__IDNT_e,g)));
3461 	    }
3462 	  }
3463 	  return true;
3464 	}
3465       }
3466       if (!act && (c=='+' || c=='-' || c=='*' || c=='/' || c=='^' || c==',' || c=='<' || c=='>' || c=='=') ){
3467 	insure_something_selected();
3468 	gen g=get_selection();
3469 	gen tmp;
3470 	if (c==','){
3471 	  if (g.type==_VECT && g.subtype==_SEQ__VECT){
3472 	    vecteur v=*g._VECTptr;
3473 	    v.push_back(zero);
3474 	    replace_selection(gen(v,g.subtype));
3475 	    select_down(0);
3476 	    select_left(0);
3477 	    return false;
3478 	  }
3479 	  gen oldg=g;
3480 	  select_up(0);
3481 	  g=get_selection();
3482 	  if (g.type==_VECT && oldg!=g){
3483 	    vecteur v=*g._VECTptr;
3484 	    v.push_back(zero);
3485 	    replace_selection(gen(v,g.subtype));
3486 	    select_down(0);
3487 	    select_left(0);
3488 	    return false;
3489 	  }
3490 	  if (g.type==_SYMB && g._SYMBptr->feuille.type==_VECT){
3491 	    bool inside=g.is_symb_of_sommet(at_of) || g.is_symb_of_sommet(at_at);
3492 	    int sub=0;
3493 	    vecteur v;
3494 	    if (inside){
3495 	      if (g._SYMBptr->feuille._VECTptr->back().type==_VECT){
3496 		v=*g._SYMBptr->feuille._VECTptr->back()._VECTptr;
3497 		sub=g._SYMBptr->feuille._VECTptr->back().subtype;
3498 	      }
3499 	      else {
3500 		v=makevecteur(g._SYMBptr->feuille._VECTptr->back());
3501 		sub=_SEQ__VECT;
3502 	      }
3503 	    }
3504 	    else
3505 	      v=*g._SYMBptr->feuille._VECTptr;
3506 	    v.push_back(zero);
3507 	    if (g._SYMBptr->sommet==at_integrate && v.size()==3)
3508 	      v.push_back(plus_one);
3509 	    gen tmp;
3510 	    if (inside)
3511 	      tmp=symbolic(g._SYMBptr->sommet,gen(makevecteur(g._SYMBptr->feuille._VECTptr->front(),gen(v,sub)),g._SYMBptr->feuille.subtype));
3512 	    else
3513 	      tmp=symbolic(g._SYMBptr->sommet,gen(v,g._SYMBptr->feuille.subtype));
3514 	    replace_selection(tmp);
3515 	    select_down(0);
3516 	    if (inside){
3517 	      select_right(0);
3518 	      select_down(0);
3519 	      select_left(0);
3520 	    }
3521 	    return false;
3522 	  }
3523 	  if (g.type==_SYMB){
3524 	    vecteur v(gen2vecteur(g._SYMBptr->feuille));
3525 	    if (v.size()==1 && (g._SYMBptr->sommet==at_integrate || g._SYMBptr->sommet==at_sum || g._SYMBptr->sommet==at_limit || g._SYMBptr->sommet==at_derive) )
3526 	      v.push_back(vx_var);
3527 	    v.push_back(zero);
3528 	    if (g._SYMBptr->sommet==at_integrate || g._SYMBptr->sommet==at_sum)
3529 	      v.push_back(plus_one);
3530 	    replace_selection(symbolic(g._SYMBptr->sommet,gen(v,_SEQ__VECT)));
3531 	    return false;
3532 	  }
3533 	  tmp=at_makesuite;
3534 	} // end if c==','
3535 	else
3536 	  tmp=gen(string("'")+char(c)+string("'"),contextptr);
3537 	if (tmp.type!=_FUNC)
3538 	  setsizeerr();
3539 	unary_function_ptr f=*tmp._FUNCptr;
3540 	if ( g.is_symb_of_sommet(at_makesuite) && ( (c!='/' && c!='^') || (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2) ) ){
3541 	  replace_selection(symbolic(f,g._SYMBptr->feuille));
3542 	  return true;
3543 	}
3544 	else {
3545 	  tmp=gen(makevecteur(g,0),_SEQ__VECT);
3546 	  // tmp=gen(makevecteur(g,Equation_nullstring()),_SEQ__VECT);
3547 	  replace_down_left_activate(symbolic(f,tmp));
3548 	  return false;
3549 	}
3550       }
3551     } // end not active or active_parse
3552     if (act){
3553       // *act is active and is a terminal of type string
3554       string s=*act->_EQWptr->g._STRNGptr;
3555       int ss=s.size();
3556       active_pos=max(min(active_pos,ss),0);
3557       vecteur * vptr;
3558       int pos;
3559       switch (c){
3560       case 0x0b:
3561 	if (active_pos>0)
3562 	  --active_pos;
3563 	else {
3564 	  pos=in_multistring(data,vptr);
3565 	  if (pos>0){ // back one line and active_pos maximal
3566 	    Equation_select(*act,false,true);
3567 	    --pos;
3568 	    Equation_select((*vptr)[pos],true,true);
3569 	    active_pos=RAND_MAX;
3570 	  }
3571 	}
3572 	return 1;
3573       case 0x0c:
3574 	if (active_pos<ss)
3575 	  ++active_pos;
3576 	else {
3577 	  pos=in_multistring(data,vptr);
3578 	  if (pos>=0 && pos<int(vptr->size()-1)){ // forward one line and active_pos maximal
3579 	    Equation_select(*act,false,true);
3580 	    ++pos;
3581 	    Equation_select((*vptr)[pos],true,true);
3582 	    active_pos=0;
3583 	  }
3584 	}
3585 	return 1;
3586       case 0x7f:
3587 	if (active_pos>0){
3588 	  s=s.substr(0,active_pos-1)+s.substr(active_pos,ss-active_pos);
3589 	  --active_pos;
3590 	}
3591 	else {
3592 	  pos=in_multistring(data,vptr);
3593 	  if (pos==-1)
3594 	    return 1;
3595 	  if (pos>0){
3596 	    handle_backspace(this,pos,vptr);
3597 	    return 1;
3598 	  }
3599 	  else {
3600 	    if (ss==0){
3601 	      act->_EQWptr->active=false;
3602 	      act->_EQWptr->selected=true;
3603 	      begin_sel=-1;
3604 	      end_sel=-1;
3605 	      remove_selection();
3606 	      return false;
3607 	    }
3608 	  }
3609 	}
3610 	break;
3611       default:
3612 	s = s.substr(0,active_pos)+char(c)+s.substr(active_pos,ss-active_pos);
3613 	++active_pos;
3614       }
3615       replace_selection(string2gen(s,false),1);
3616       return false;
3617     }
3618     // nothing active
3619     bool has_selection=false;
3620     gen g=Equation_selected2gen(this,data,has_selection);
3621     if (has_selection){
3622       string tmp(1,c);
3623       gen tmps=string2gen(tmp,false);
3624       tmps.subtype=1;
3625       if (replace_selection(tmps)){
3626 	// if nothing active, activate
3627 	attributs a(0,0,0);
3628 	vecteur position;
3629 	gen * ptr =Equation_selected(data,a,w(),position,1,contextptr);
3630 	if (!ptr){
3631 	  deselect_and_activate();
3632 	  active_pos=1;
3633 	}
3634 	if (in_multistring(data)==-1 && g.type!=_STRNG)
3635 	  need_active_parse=true;
3636       }
3637       return false;
3638     }
3639     // nothing selected
3640     select_up(0);
3641     return true;
3642   }
3643 
3644   /* not used // return true if conversion needed and done
3645   bool string2vector(const string & s,vector<string> & v){
3646     int pos=s.find('\n'),newpos;
3647     int ss=s.size();
3648     if (pos<0 || pos >= ss)
3649       return false;
3650     v.clear();
3651     v.push_back(s.substr(0,pos));
3652     for (;pos<ss;){
3653       newpos=s.find('\n',pos);
3654       if (newpos<0 || newpos >= ss){
3655 	v.push_back(s.substr(pos,ss-pos));
3656 	return true;
3657       }
3658       v.push_back(s.substr(pos,newpos-pos));
3659       pos=newpos;
3660     }
3661   }
3662   */
3663 
handle_text(const string & paste_s_orig,gen * act)3664   bool Equation::handle_text(const string & paste_s_orig,gen * act){
3665     const giac::context * contextptr = get_context(this);
3666     string paste_s(paste_s_orig);
3667     int ps=paste_s.size();
3668     if (ps>2 && paste_s[0]=='"' && paste_s[ps-1]=='"'){
3669       ps = ps-2;
3670       paste_s=paste_s.substr(1,ps);
3671     }
3672     int nl=paste_s.find('\n');
3673     bool needmulti=(nl>=0 && nl<ps);
3674     if (act){ // insert s
3675       string s;
3676       if (act->type!=_EQW || act->_EQWptr->g.type!=_STRNG){
3677 	cerr << "Error " << *act << '\n';
3678 	return false;
3679       }
3680       s=*act->_EQWptr->g._STRNGptr;
3681       int pos=giacmax(giacmin(active_pos,s.size()),0);
3682       active_pos=pos;
3683       int toend=s.size()-pos;
3684       s=s.substr(0,active_pos)+paste_s+s.substr(active_pos,toend);
3685       gen g(s,contextptr);
3686       if (giac::first_error_line(contextptr))
3687 	g=string2gen(s,false);
3688       if (!needmulti){
3689 	if (replace_selection(g,1))
3690 	  active_pos = pos+paste_s.size();
3691 	return false;
3692       }
3693       vecteur * vptr;
3694       int n=in_multistring(data,vptr);
3695       if (n==-1){
3696 	if (need_active_parse)
3697 	  g=symbolic(at_expr,g);
3698 	desactivate_and_select();
3699 	if (replace_selection(g)){
3700 	  if (need_active_parse)
3701 	    select_down(0);
3702 	  select_down(0);
3703 	  select_left(0);
3704 	  pos = get_selection()._STRNGptr->size()-toend;
3705 	  deselect_and_activate();
3706 	  active_pos = max(pos,0);
3707 	  need_active_parse=false;
3708 	}
3709 	return false;
3710       }
3711       // insert in current multistring
3712       s="";
3713       const_iterateur it=vptr->begin(),itend=vptr->end()-1;
3714       for (int i=0;i<n;++i,++it){
3715 	if (it->type==_EQW && it->_EQWptr->g.type==_STRNG)
3716 	  s += *it->_EQWptr->g._STRNGptr + '\n';
3717       }
3718       string ss=*act->_EQWptr->g._STRNGptr;
3719       s += ss.substr(0,active_pos)+paste_s+ss.substr(active_pos,ss.size()-active_pos);
3720       for (++it;it!=itend;++it){
3721 	if (it->type==_EQW && it->_EQWptr->g.type==_STRNG)
3722 	  s += '\n'+*it->_EQWptr->g._STRNGptr;
3723       }
3724       g=gen(s,contextptr);
3725       if (giac::first_error_line(contextptr))
3726 	g=string2gen(s,false);
3727       desactivate_and_select();
3728       // count newline in paste_s, add to n, activate this line, cursor
3729       // at end of this line - the value of toend
3730       for (int i=0;i<ps;++i){
3731 	if (paste_s[i]=='\n')
3732 	  ++n;
3733       }
3734       select_up(0);
3735       vecteur position;
3736       attributs tmpattr(0,0,0);
3737       gen * ptr = Equation_selected(data,tmpattr,w(),position,false,contextptr);
3738       eqwdata olde=Equation_total_size(*ptr);
3739       * ptr = Equation_compute_size(g,olde.eqw_attributs,w(),contextptr);
3740       Equation_select(data,false);
3741       Equation_select((*ptr->_VECTptr)[n],true);
3742       g=get_selection();
3743       if (g.type==_STRNG){
3744 	pos = g._STRNGptr->size();
3745 	deselect_and_activate();
3746 	need_active_parse = false;
3747 	if (replace_selection(g,1))
3748 	  active_pos = max(pos- toend,0) ;
3749 	need_active_parse = false;
3750       }
3751       return false;
3752     }
3753     // remove selection and replace
3754     gen g(paste_s,contextptr);
3755     if (giac::first_error_line(contextptr))
3756       g=string2gen(paste_s,false);
3757     if (needmulti)
3758       g=symbolic(at_expr,g);
3759     replace_selection(g);
3760     return true;
3761   }
3762 
handle_text(const string & paste_s_orig)3763   bool Equation::handle_text(const string & paste_s_orig){
3764     vecteur position;
3765     const giac::context * contextptr = get_context(this);
3766     gen * act=Equation_selected(data,attr,w(),position,1,contextptr);
3767     return handle_text(paste_s_orig,act);
3768   }
3769 
3770   // activate at x,y, return cursor position or -1, or -3 for fl_widget_pointer
Equation_set_active(int x,int y,gen & g,Equation * eq,bool inmultistring,gen * & activecellptr)3771   int Equation_set_active(int x,int y,gen & g,Equation * eq,bool inmultistring,gen * & activecellptr){
3772     const giac::context * contextptr = get_context(eq);
3773     activecellptr=0;
3774     if (g.type==_EQW){
3775       // x,y must be in the box
3776       eqwdata & e=*g._EQWptr;
3777       if (e.x>x || e.x+e.dx<x || e.y>y || e.y+e.dy<y)
3778 	return -1;
3779       activecellptr=&e.g;
3780       if (e.g.type==_POINTER_){
3781 	return -3;
3782       }
3783       e.active=true;
3784       if (e.g.type==_STRNG)
3785 	eq->need_active_parse=!inmultistring && e.g._STRNGptr->empty();
3786       else {
3787 	eq->need_active_parse=true;
3788 	e.g=string2gen(e.g.print(contextptr),false);
3789 	e.g.subtype=1;
3790       }
3791       // binary search for active_pos
3792       return Equation_binary_search_pos(e,x,y);
3793     }
3794     if (g.type!=_VECT)
3795       return -1;
3796     vecteur & v =*g._VECTptr;
3797     if (v.empty())
3798       return -1;
3799     iterateur it=v.begin(),itend=v.end()-1;
3800     if (!inmultistring)
3801       inmultistring = itend->type==_EQW && itend->_EQWptr->g==at_multistring;
3802     int pos;
3803     for (;it!=itend;++it){
3804       pos=Equation_set_active(x,y,*it,eq,inmultistring,activecellptr);
3805       if (pos!=-1){
3806 	return pos;
3807       }
3808     }
3809     if (it->type==_EQW){ // change operator
3810       eqwdata & e=*it->_EQWptr;
3811       if (e.x>x || e.x+e.dx<x || e.y>y || e.y+e.dy<y)
3812 	return -1;
3813       if ((eq && !eq->output_equation) && e.g.type==_FUNC && !e.g._FUNCptr->ptr()->printsommet && e.g!=at_makesuite && e.g!=at_makelist && e.g!=at_makevector ){
3814 	eqwdata f(e);
3815 	f.g=string2gen(e.g._FUNCptr->ptr()->s,false);
3816 	int pos=Equation_binary_search_pos(f,x,y);
3817 	string ans,debut=f.g._STRNGptr->substr(0,pos);
3818 	if (handle_tab(debut,*giac::vector_completions_ptr(),eq->h()/2,eq->w()/2,pos,ans)){
3819 	  gen tmp(ans,contextptr);
3820 	  if (tmp.type==_SYMB){
3821 	    e.g=tmp._SYMBptr->sommet;
3822 	    return -2;
3823 	  }
3824 	  tmp=gen("'"+ans+"'",contextptr);
3825 	  if (tmp.type==_FUNC){
3826 	    e.g=tmp;
3827 	    return -2;
3828 	  }
3829 	}
3830       }
3831     }
3832     return -1;
3833   }
set_active(int x,int y)3834   gen * Equation::set_active(int x,int y){
3835     const giac::context * contextptr = get_context(this);
3836     deselect();
3837     gen * gptr;
3838     int pos=Equation_set_active(x,y,data,this,false,gptr);
3839     if (pos==-3)
3840       return gptr;
3841     if (pos==-2){
3842       data=Equation_compute_size(get_data(),attr,w(),contextptr);
3843       select();
3844       redraw();
3845       return 0;
3846     }
3847     if (pos==-1)
3848       Equation_select(data,false,true);
3849     else
3850       active_pos=pos;
3851     return 0;
3852   }
3853 
3854   // Return 0 if the mouse cursor is not on a _POINTER_ object,
3855   // returns a pointer to the gen of type _POINTER_ otherwise
Equation_is_pointer_active(Equation * eq,const gen & g,int x,int y)3856   gen * Equation_is_pointer_active(Equation * eq,const gen & g,int x,int y){
3857     if (g.type==_EQW){
3858       // x,y must be in the box
3859       eqwdata & e=*g._EQWptr;
3860       if (e.x>x || e.x+e.dx<x || e.y>y || e.y+e.dy<y)
3861 	return 0;
3862       if (e.g.type==_POINTER_)
3863 	return &e.g;
3864       return 0;
3865     }
3866     if (g.type!=_VECT)
3867       return 0;
3868     vecteur & v =*g._VECTptr;
3869     if (v.empty())
3870       return 0;
3871     iterateur it=v.begin(),itend=v.end()-1;
3872     gen * pos;
3873     for (;it!=itend;++it){
3874       pos=Equation_is_pointer_active(eq,*it,x,y);
3875       if (pos)
3876 	return pos;
3877     }
3878     return 0;
3879   }
3880 
3881   // for multistring Up and Down should not select
Equation_multistring_activate(Equation * eq,int direction,int pos)3882   void Equation_multistring_activate(Equation * eq,int direction,int pos){
3883     gen save_data=Equation_copy(eq->data);
3884     if (direction)
3885       eq->select_down(1);
3886     else
3887       eq->select_up(1);
3888     if (eq->get_selection().type==_STRNG){
3889       eq->deselect_and_activate();
3890       eq->active_pos=max(pos,0);
3891     }
3892     else {
3893       eq->data=save_data;
3894       eq->adjust_xy_sel();
3895     }
3896   }
3897 
3898   // return -1 if not in a multistring, position otherwise
in_multistring(const gen & data,vecteur * & vptr)3899   int in_multistring(const gen & data,vecteur * & vptr){
3900     if (data.type!=_VECT)
3901       return -1;
3902     vecteur & v =*data._VECTptr;
3903     iterateur it=v.begin(),itend=v.end();
3904     if (itend==it)
3905       return -1;
3906     --itend;
3907     if (itend->type==_EQW && itend->_EQWptr->g==at_multistring){
3908       for (;it!=itend;++it){
3909 	if (it->type==_EQW && it->_EQWptr->active){
3910 	  vptr = &v;
3911 	  return it-v.begin();
3912 	}
3913       }
3914       return -1;
3915     }
3916     for (;it!=itend;++it){
3917       int i=in_multistring(*it,vptr);
3918       if (i!=-1)
3919 	return i;
3920     }
3921     return -1;
3922   }
3923 
3924   // return -1 if not in a multistring, position otherwise
in_multistring(const gen & data)3925   int in_multistring(const gen & data){
3926     vecteur * vptr;
3927     return in_multistring(data,vptr);
3928   }
3929 
handle_newline(Equation * eqwptr)3930   void handle_newline(Equation * eqwptr){
3931     const giac::context * contextptr = get_context(eqwptr);
3932     vecteur * vptr;
3933     int n=in_multistring(eqwptr->data,vptr);
3934     if (n!=-1){
3935       // add a new line here
3936       string s( *(*vptr)[n]._EQWptr->g._STRNGptr);
3937       int ss=s.size(),pos=max(min(eqwptr->active_pos,ss),0);
3938       string s1=s.substr(0,pos);
3939       string s2=s.substr(pos,ss-pos);
3940       (*vptr)[n]=Equation_compute_size(string2gen(s1,false),eqwptr->attr,0,contextptr);
3941       iterateur it=vptr->begin()+(n+1);
3942       vptr->insert(it,Equation_compute_size(string2gen(s2,false),eqwptr->attr,0,contextptr));
3943       Equation_select((*vptr)[n],false,true); // desactivate line n
3944       Equation_select((*vptr)[n+1],true,true); // activate line n+1
3945       eqwptr->active_pos=0;
3946       eqwptr->replace_selection(string2gen(s2,false),1);
3947     }
3948     else {
3949       // not in a multistring, transform current in a multistring
3950       bool parse=eqwptr->need_active_parse;
3951       eqwptr->need_active_parse=false;
3952       eqwptr->desactivate_and_select();
3953       gen g=eqwptr->get_selection();
3954       if (g.type==_STRNG)       // FIXME: should add newline at active_pos
3955 	g=string2gen(*g._STRNGptr+'\n',false);
3956       bool res;
3957       if (parse){
3958 	g=symbolic(at_expr,g);
3959 	res=eqwptr->replace_selection(g);
3960 	eqwptr->select_down(0);
3961       }
3962       else {
3963 	res=eqwptr->replace_selection(g);
3964       }
3965       if (res){
3966 	eqwptr->select_down(0);
3967 	eqwptr->select_right(0);
3968 	eqwptr->deselect_and_activate();
3969 	eqwptr->need_active_parse=false;
3970       }
3971     }
3972   }
3973 
switch_expr(Equation * eqwptr)3974   bool switch_expr(Equation * eqwptr){
3975     gen g=eqwptr->get_selection();
3976     if (g.type==_STRNG){
3977       eqwptr->replace_selection(symbolic(at_expr,g));
3978       return true;
3979     }
3980     if (g.is_symb_of_sommet(at_expr)){
3981       eqwptr->replace_selection(g._SYMBptr->feuille);
3982       return true;
3983     }
3984     return false;
3985   }
3986 
handle(int event)3987   int Equation::handle(int event){
3988     if (event==FL_MOUSEWHEEL){
3989       eqwdata e=Equation_total_size(data);
3990       if (Fl::event_inside(this) && vscroll && h()<e.dy){
3991 	int n=Fl::e_dy;
3992 	int v=vscroll->value();
3993 	if (n<0 && v==0)
3994 	  return 0;
3995 	if (n>0 && v>e.dy-h()+1)
3996 	  return 0;
3997 	return vscroll->handle(event);
3998       }
3999       else
4000 	return 0;
4001     }
4002     xcas::History_Pack * hp=get_history_pack(this);
4003     giac::context * cptr=hp?hp->contextptr:0;
4004     if (is_context_busy(cptr)){
4005       thread_param * ptr= thread_param_ptr(cptr);
4006       if (ptr && ptr->f_param==this) // handle is locked during eval
4007 	return 1;
4008     }
4009     int i=Fl_Group::handle(event);
4010     if (i)
4011       return i;
4012     i=in_handle(event);
4013     if (i==-1)
4014       return 1;
4015     //    if (i)
4016     //  Fl::focus(this);
4017     return i;
4018   }
4019 
in_handle(int event)4020   int Equation::in_handle(int event){
4021     const giac::context * contextptr = get_context(this);
4022     if (event==FL_FOCUS || event==FL_PUSH){
4023       redraw();
4024       Xcas_input_focus=this;
4025       Fl::focus(this);
4026       if (event==FL_FOCUS)
4027 	return 1;
4028     }
4029     if (event==FL_KEYBOARD)
4030       Xcas_input_focus=this;
4031     bool is_history=(data.type==_VECT && data.subtype==_HIST__VECT);
4032     bool complete_level_selected=false;
4033     eqwdata data_eqwdata=Equation_total_size(data);
4034     if (is_history){ // check if a complete level is selected
4035       const_iterateur it=data._VECTptr->begin(),itend=data._VECTptr->end();
4036       for (;it!=itend;++it){
4037 	eqwdata e=Equation_total_size(*it);
4038 	if (e.selected){
4039 	  complete_level_selected=true;
4040 	  break;
4041 	}
4042       }
4043     }
4044     attributs attr;
4045     vecteur position;
4046     gen f,* act=Equation_selected(data,attr,w(),position,1,contextptr);
4047     char ch;
4048     if (act && act->type==_EQW && act->_EQWptr->g.type==_STRNG)
4049       ;
4050     else
4051       act=0;
4052     if (event==FL_RELEASE && Fl::event_button()== FL_MIDDLE_MOUSE ){
4053       int x,y;
4054       x=Fl::event_x()-this->x()+xleft;
4055       y=Fl::event_y()-this->y();
4056       deselect();
4057       gen * gptr=set_active(x,ytop-y);
4058       if (gptr && gptr->type==_POINTER_)
4059 	// should call the handle method of the pointer
4060 	return 1;
4061       Fl::paste(*this);
4062       return 1;
4063     }
4064     if (event==FL_PASTE) {
4065       handle_text(Fl::event_text(),act);
4066       return 1;
4067     }
4068     if (event==FL_KEYBOARD){
4069       /* if (Fl::event_state()== FL_CTRL || Fl::event_state()== FL_ALT)
4070 	 return 0; */
4071       bool sel_changed=true;
4072       bool shifton= (Fl::event_state()== FL_SHIFT );
4073       int mode=Fl::event_state(FL_CTRL);
4074       if (mode)
4075 	mode=2;
4076       else
4077 	mode=shifton?0:1;
4078       int save_active_pos=active_pos;
4079       switch (Fl::event_key()){
4080       case FL_Left:
4081 	if (act)
4082 	  handle_key(0x0b,act);
4083 	else {
4084 	  if (!parse_desactivate())
4085 	    select_left(mode); // it was shift_on
4086 	}
4087 	break;
4088       case FL_Right:
4089 	if (act)
4090 	  handle_key(0x0c,act);
4091 	else {
4092 	  if (!parse_desactivate())
4093 	    select_right(mode);
4094 	}
4095 	break;
4096       case FL_Up:
4097 	if (shifton && complete_level_selected){
4098 	  select_left(0);
4099 	  select_left(0);
4100 	}
4101 	else {
4102 	  if (!parse_desactivate())
4103 	    select_up(!shifton);
4104 	  else
4105 	    if (!shifton)
4106 	      Equation_multistring_activate(this,0,save_active_pos);
4107 	}
4108 	break;
4109       case FL_Down:
4110 	if (shifton && complete_level_selected){
4111 	  select_right(0);
4112 	  select_right(0);
4113 	}
4114 	else {
4115 	  if (!parse_desactivate())
4116 	    select_down(!shifton);
4117 	  else
4118 	    if (!shifton)
4119 	      Equation_multistring_activate(this,1,save_active_pos);
4120 	}
4121 	break;
4122       case FL_Escape:
4123 	if (cb_escape)
4124 	  cb_escape(this);
4125 	else
4126 	  parse_desactivate();
4127 	redraw();
4128 	return 1;
4129       case FL_Shift_L: case FL_Shift_R:
4130       case FL_Caps_Lock:
4131       case FL_Meta_L: case FL_Meta_R: case FL_Menu: case FL_Num_Lock:
4132       case FL_Insert:
4133 	return 1;
4134       case FL_Control_R: case FL_Control_L: case FL_Alt_L: case FL_Alt_R:
4135 	return 0;
4136       case FL_BackSpace:
4137       case FL_Delete:
4138 	if (is_history && complete_level_selected && cb_backspace){
4139 	  cb_backspace(this);
4140 	  return 1;
4141 	}
4142 	if (modifiable){
4143 	  if (act){
4144 	    handle_key(0x7f,act);
4145 	    return 1;
4146 	  }
4147 	  else {
4148 	    f=get_selection();
4149 	    if (f.type==_SYMB){
4150 	      f=f._SYMBptr->feuille;
4151 	      if (f.type==_VECT && !f.subtype && !ckmatrix(f))
4152 		f.subtype=_SEQ__VECT;
4153 	      replace_selection(f);
4154 	    }
4155 	    else
4156 	      remove_selection();
4157 	  }
4158 	}
4159 	break;
4160       case FL_Enter: case FL_KP_Enter:
4161 	/*
4162 	if (old_upper_window_state==upper_window_mtrw){
4163 	  manage_upper_window(upper_window_mtrw,false);
4164 	}
4165 	else {
4166 	  manage_upper_window(upper_window_hist,false);
4167 	}
4168 	input_value(eqw_data2gen(data).print(contextptr).c_str());
4169 	*/
4170 	if (shifton)
4171 	  handle_newline(this);
4172 	else {
4173 	  if (cb_enter)
4174 	    cb_enter(this,0);
4175 	  else
4176 	    parse_desactivate();
4177 	}
4178 	redraw();
4179 	return 1;
4180       case FL_Home:
4181 	xleft=data_eqwdata.x;
4182 	sel_changed=false;
4183 	break;
4184       case FL_End:
4185 	xleft=data_eqwdata.x+data_eqwdata.dx-w();
4186 	sel_changed=false;
4187 	break;
4188       case FL_Page_Up:
4189 	ytop -= h();
4190 	sel_changed=false;
4191 	break;
4192       case FL_Page_Down:
4193 	ytop += h();
4194 	sel_changed=false;
4195 	break;
4196       default:
4197 	if (modifiable){
4198 	  ch=Fl::event_text()?Fl::event_text()[0]:0;
4199 	  int es=Fl::event_state();
4200 	  if (es== FL_ALT || es==1572864){
4201 	    return 0;
4202 	    // ??
4203 	    if (ch=='v'){
4204 	      gen e;
4205 	      select_user_var(100,200,e,0);
4206 	      if (output_equation){
4207 		if (!parse_desactivate())
4208 		  insure_something_selected(true);
4209 		eval_function(e);
4210 	      }
4211 	      return 1;
4212 	    }
4213 	  }
4214 	  if (ch==1){ // Ctrl-A select all
4215 	    select();
4216 	    fl_select();
4217 	    return 1;
4218 	  }
4219 	  if (ch==3) { // Ctrl-C
4220 	    static string s;
4221 	    s=get_selection().print(contextptr);
4222 	    Fl::copy(s.c_str(),s.size(),1);
4223 	    return 1;
4224 	  }
4225 	  if (ch==18){ // Ctrl-R
4226 	    in_Xcas_input_1arg(this,"integrate");
4227 	    return 1;
4228 	  }
4229 	  if (ch==19){ // Ctrl-S
4230 	    if (!parse_desactivate())
4231 	      insure_something_selected(true);
4232 	    eval_function(at_simplify);
4233 	    return 1;
4234 	  }
4235 	  if (ch==4){ // Ctrl-D
4236 	    in_Xcas_input_1arg(this,"diff");
4237 	    return 1;
4238 	  }
4239 	  if (ch==5){ // Ctrl-E
4240 	    if (!parse_desactivate())
4241 	      insure_something_selected(true);
4242 	    eval_function(at_eval);
4243 	    return 1;
4244 	  }
4245 	  if (ch==6){ // Ctrl-F
4246 	    if (!parse_desactivate())
4247 	      insure_something_selected(true);
4248 	    eval_function(at_factor);
4249 	    return 1;
4250 	  }
4251 	  if (ch==12){ // Ctrl-L
4252 	    in_Xcas_input_1arg(this,"limit");
4253 	    return 1;
4254 	  }
4255 	  if (ch==14){ // Ctrl-N
4256 	    if (!parse_desactivate())
4257 	      insure_something_selected(true);
4258 	    eval_function(at_normal);
4259 	    return 1;
4260 	  }
4261 	  if (ch==16){ // Ctrl-P
4262 	    if (!parse_desactivate())
4263 	      insure_something_selected(true);
4264 	    eval_function(at_partfrac);
4265 	    return 1;
4266 	  }
4267 	  if (ch>=17 && ch<=20) // Ctrl-Q T
4268 	    return 0;
4269 	  if (ch==22){ // Ctrl-V
4270 	    Fl::paste(*this,1);
4271 	    return 1;
4272 	  }
4273 	  if (ch==26){ // Ctrl-Z
4274 	    rcl_data(-1);
4275 	    adjust_widget_size();
4276 	    return 1;
4277 	  }
4278 	  if (ch==25){ // Ctrl-Y
4279 	    rcl_data(1);
4280 	    adjust_widget_size();
4281 	    return 1;
4282 	  }
4283 	  if (ch==9){ // tab, ctrl-I
4284 	    string s,ans;
4285 	    if (act){
4286 	      s=*act->_EQWptr->g._STRNGptr;
4287 	      int ss=s.size();
4288 	      active_pos=max(min(active_pos,ss),0);
4289 	      string fin=s.substr(active_pos,s.size()-active_pos);
4290 	      s=s.substr(0,active_pos);
4291 	      int remove=active_pos;
4292 	      if (handle_tab(s,(*vector_completions_ptr()),h()/2,w()/2,remove,ans)){
4293 		int l=s.size()-remove;
4294 		if (l<0)
4295 		  l=0;
4296 		ans=s.substr(0,l)+ans;
4297 		replace_selection(string2gen(ans+fin,false),1);
4298 		active_pos=ans.size();
4299 		return 1;
4300 	      }
4301 	    }
4302 	    else {
4303 	      insure_something_selected();
4304 	      gen gs=get_selection();
4305 	      s=gs.print(contextptr);
4306 	      int pos=s.find('(');
4307 	      if (pos>0 && pos<int(s.size()))
4308 		s=s.substr(0,pos);
4309 	      int remove;
4310 	      if (gs.type==_SYMB && handle_tab(s,(*vector_completions_ptr()),h()/2,w()/2,remove,ans)){
4311 		// FIXME remove remove chars
4312 		gen gf=gen("'"+s+ans+"'",contextptr);
4313 		if (gf.type==_FUNC)
4314 		  replace_selection(symbolic(*gf._FUNCptr,gs._SYMBptr->feuille));
4315 	      }
4316 	    }
4317 	    return 1;
4318 	  }
4319 	  if (ch=='"'){
4320 	    if (act &&  in_multistring(data)==-1){
4321 	      // change mode, ! in multistring
4322 	      need_active_parse=!need_active_parse;
4323 	      redraw();
4324 	      return 1;
4325 	    }
4326 	    if (switch_expr(this)){
4327 	      redraw();
4328 	      return 1;
4329 	    }
4330 	    else {
4331 	      gen g=get_selection();
4332 	      replace_selection(string2gen(g.print(),false));
4333 	      deselect_and_activate();
4334 	      need_active_parse=true;
4335 	      return 1;
4336 	    }
4337 	  }
4338 	  sel_changed=handle_key(ch,act);
4339 	} // end if (modifiable)
4340       }
4341       if (sel_changed){
4342 	fl_select();
4343 	setscroll();
4344       }
4345       return 1;
4346     } // end event==FL_KEYBOARD
4347     int x,y;
4348     x=Fl::event_x() - this->x() +xleft;
4349     y=Fl::event_y() - this->y();
4350     if (event==FL_PUSH ){
4351       if ( (vscroll->visible() && (Fl::event_x() - this->x()>w()-vscroll->w()) )
4352 	   || (hscroll->visible() && (y>h()-hscroll->h())) ){
4353 	return 0;
4354       }
4355       if (Fl::event_button()!= FL_MIDDLE_MOUSE)
4356 	// desactivate active cell if any
4357 	parse_desactivate();
4358       xsel=x;
4359       ysel=ytop-y;
4360       xcur=xsel;
4361       ycur=ysel;
4362       if (Fl::event_button()!= FL_MIDDLE_MOUSE)
4363 	deselect();
4364       redraw();
4365       gen * gptr=Equation_is_pointer_active(this,data,x,ytop-y);
4366       if (gptr && gptr->type==_POINTER_ && gptr->subtype==_FL_WIDGET_POINTER){
4367 	// call the handle method of the pointer
4368 	Fl_Widget * flptr=(Fl_Widget *) gptr->_POINTER_val;
4369 	flptr->handle(event);
4370 	Fl::focus(this);
4371 	return 1;
4372       }
4373       return 1;
4374     }
4375     if (event==FL_DRAG){
4376       if (Fl::event_button()!= FL_MIDDLE_MOUSE)
4377 	deselect();
4378       redraw();
4379       if ( (absint(xsel-x)<=2) && (absint(ysel-(ytop-y))<2) ){
4380 	redraw();
4381 	return 1;
4382       }
4383       gen * gptr=Equation_is_pointer_active(this,data,x,ytop-y);
4384       if (gptr && gptr->type==_POINTER_ && gptr->subtype==_FL_WIDGET_POINTER){
4385 	// call the handle method of the pointer
4386 	Fl_Widget * flptr=(Fl_Widget *) gptr->_POINTER_val;
4387 	flptr->handle(event);
4388 	Fl::focus(this);
4389 	return 1;
4390       }
4391       if (Fl::event_button()!= FL_MIDDLE_MOUSE)
4392 	select_rectangle(x,ytop-y);
4393       return 1;
4394     }
4395     if (event==FL_RELEASE){
4396       Fl::focus(this);
4397       deselect();
4398       redraw();
4399       gen * gptr=Equation_is_pointer_active(this,data,x,ytop-y);
4400       if (gptr && gptr->type==_POINTER_ && gptr->subtype==_FL_WIDGET_POINTER){
4401 	// call the handle method of the pointer
4402 	Fl_Widget * flptr=(Fl_Widget *) gptr->_POINTER_val;
4403 	flptr->handle(event);
4404 	Fl::focus(this);
4405 	return 1;
4406       }
4407       if ( (absint(xsel-x)<=2) && (absint(ysel-(ytop-y))<2) ){
4408 	if (Fl::event_clicks()){ // double-click
4409 	  // x=xsel+10;
4410 	  // y=ytop-ysel+4;
4411 	  desactivate_and_select();
4412 	  //gen g=get_selection();
4413 	  select_rectangle(x,ytop-y);
4414 	}
4415 	else
4416 	  gen * gptr=set_active(x,ytop-y);
4417 	return 1;
4418       }
4419       select_rectangle(x,ytop-y);
4420       if (Fl::event_button()!= FL_MIDDLE_MOUSE)
4421 	fl_select();
4422       return 1;
4423     }
4424     return 0;
4425   }
4426 
cb_Equation_Select(Fl_Menu_ * m,void *)4427   static void cb_Equation_Select(Fl_Menu_* m , void*) {
4428     if (m){
4429       Equation * eq = dynamic_cast<Equation *>(m->parent());
4430       const giac::context * contextptr = get_context(eq);
4431       if (eq){
4432 	Fl::focus(eq);
4433 	Xcas_input_focus=eq;
4434 	string s =eq->get_data().print(contextptr);
4435 	Fl::selection(*eq,s.c_str(),s.size());
4436 	eq->select();
4437 	eq->redraw();
4438       }
4439     }
4440   }
4441 
Equation_eval_callback(const giac::gen & evaled_g,void * param)4442   void Equation_eval_callback(const giac::gen & evaled_g,void * param){
4443     Fl_Widget * wid=static_cast<Fl_Widget *>(param);
4444     if (!wid)
4445       return;
4446     Equation * eq = dynamic_cast<Equation *>(wid);
4447     if (!eq)
4448       return;
4449     Xcas_input_focus=eq;
4450     eq->replace_selection_wo_save(evaled_g);
4451   }
4452 
cb_Equation_Function(Fl_Menu_ * m,const unary_function_ptr * u)4453   void cb_Equation_Function(Fl_Menu_* m ,const unary_function_ptr * u) {
4454     if (m){
4455       Equation * eq = dynamic_cast<Equation *>(m->parent());
4456       if (eq){
4457 	Fl::focus(eq);
4458 	Xcas_input_focus=eq;
4459 	eq->save_data();
4460 	xcas::History_Pack * hp=get_history_pack(eq);
4461 	giac::context * cptr=hp?hp->contextptr:0;
4462 	make_thread(symbolic(u,eq->get_selection()),eval_level(cptr),Equation_eval_callback,eq,cptr);
4463       }
4464     }
4465   }
4466 
cb_Equation_Evalf(Fl_Menu_ * m,void *)4467   static void cb_Equation_Evalf(Fl_Menu_* m , void*) {
4468     cb_Equation_Function(m,at_evalf);
4469   }
4470 
cb_Equation_Eval(Fl_Menu_ * m,void *)4471   static void cb_Equation_Eval(Fl_Menu_* m , void*) {
4472     cb_Equation_Function(m,at_eval);
4473   }
4474 
cb_Equation_Exact(Fl_Menu_ * m,void *)4475   static void cb_Equation_Exact(Fl_Menu_* m , void*) {
4476     cb_Equation_Function(m,at_exact);
4477   }
4478 
cb_Equation_Simplify(Fl_Menu_ * m,void *)4479   static void cb_Equation_Simplify(Fl_Menu_* m , void*) {
4480     cb_Equation_Function(m,at_simplify);
4481   }
4482 
4483 
cb_Equation_Editselection(Fl_Menu_ * m,void *)4484   static void cb_Equation_Editselection(Fl_Menu_* m , void*) {
4485     if (m){
4486       Equation * eq = dynamic_cast<Equation *>(m->parent());
4487       if (eq){
4488 	Fl::focus(eq);
4489 	Xcas_input_focus=eq;
4490 	eq->save_data();
4491 	xcas::History_Pack * hp=get_history_pack(eq);
4492 	giac::context * cptr=hp?hp->contextptr:0;
4493 	gen g=eq->get_selection();
4494 	eq->replace_selection(string2gen(g.print(),false));
4495 	eq->deselect_and_activate();
4496 	eq->need_active_parse=true;
4497       }
4498     }
4499   }
4500 
cb_Equation_Normal(Fl_Menu_ * m,void *)4501   static void cb_Equation_Normal(Fl_Menu_* m , void*) {
4502     cb_Equation_Function(m,at_normal);
4503   }
4504 
cb_Equation_Factor(Fl_Menu_ * m,void *)4505   static void cb_Equation_Factor(Fl_Menu_* m , void*) {
4506     cb_Equation_Function(m,at_factor);
4507   }
4508 
cb_Equation_Back(Fl_Menu_ * m,void *)4509   static void cb_Equation_Back(Fl_Menu_* m , void*) {
4510     if (m){
4511       Equation * eq = dynamic_cast<Equation *>(m->parent());
4512       if (eq){
4513 	Xcas_input_focus=eq;
4514 	eq->rcl_data(-1);
4515       }
4516     }
4517   }
4518 
cb_Equation_Forward(Fl_Menu_ * m,void *)4519   static void cb_Equation_Forward(Fl_Menu_* m , void*) {
4520     if (m){
4521       Equation * eq = dynamic_cast<Equation *>(m->parent());
4522       if (eq){
4523 	Xcas_input_focus=eq;
4524 	eq->rcl_data(1);
4525       }
4526     }
4527   }
4528 
4529   Fl_Menu_Item Equation_menu[] = {
4530     {gettext("M"), 0,  0, 0, 64, 0, 0, 14, 56},
4531     {gettext("Select all"), 0,  (Fl_Callback*)cb_Equation_Select, 0, 0, 0, 0, 14, 56},
4532     {gettext("Edit selection"), 0,  (Fl_Callback*)cb_Equation_Editselection, 0, 0, 0, 0, 14, 56},
4533     {gettext("simplify"), 0,  (Fl_Callback*)cb_Equation_Simplify, 0, 0, 0, 0, 14, 56},
4534     {gettext("normal"), 0,  (Fl_Callback*)cb_Equation_Normal, 0, 0, 0, 0, 14, 56},
4535     {gettext("factor"), 0,  (Fl_Callback*)cb_Equation_Factor, 0, 0, 0, 0, 14, 56},
4536     {gettext("approx"), 0,  (Fl_Callback*)cb_Equation_Evalf, 0, 0, 0, 0, 14, 56},
4537     {gettext("exact"), 0,  (Fl_Callback*)cb_Equation_Exact, 0, 0, 0, 0, 14, 56},
4538     {gettext("eval"), 0,  (Fl_Callback*)cb_Equation_Eval, 0, 0, 0, 0, 14, 56},
4539     {gettext("Back"), 0,  (Fl_Callback*)cb_Equation_Back, 0, 0, 0, 0, 14, 56},
4540     {gettext("Forward"), 0,  (Fl_Callback*)cb_Equation_Forward, 0, 0, 0, 0, 14, 56},
4541     {0},
4542     {0}
4543   };
4544 
add_scroll_menu()4545   void Equation::add_scroll_menu(){
4546     int largeur=labelsize();
4547     vscroll=new Equation_Scrollbar(x()+Fl_Group::w()-largeur,y(),largeur,Fl_Group::h()-labelsize(),this,true);
4548     vscroll->labelsize(largeur);
4549     hscroll=new Equation_Scrollbar(x(),y()+Fl_Group::h()-labelsize(),Fl_Group::w()-2*largeur,labelsize(),this,false);
4550     hscroll->labelsize(largeur);
4551     Fl_Group::add(vscroll);
4552     Fl_Group::add(hscroll);
4553     menubar = new Fl_Menu_Bar(hscroll->x()+hscroll->w(),hscroll->y(),this->w()-hscroll->w(),hscroll->h());
4554     int s= Equation_menu->size();
4555     Fl_Menu_Item * menuitem = new Fl_Menu_Item[s];
4556     for (int i=0;i<s;++i)
4557       *(menuitem+i)=*(Equation_menu+i);
4558     menubar->menu (menuitem);
4559     menubar->tooltip(gettext("Equation menu"));
4560     Fl_Group::add(menubar);
4561     setscroll();
4562   }
4563 
Equation(int x,int y,int w,int h,const char * ch)4564   Equation::Equation(int x, int y, int w, int h,const char * ch): Fl_Group(x, y, max(w,20), max(h,20)){
4565     xleft=0;
4566     ytop=h;
4567     xcur=0;
4568     ycur=0;
4569     begin_sel=-1;
4570     end_sel=-1;
4571     cb_escape=0;
4572     cb_enter=0;
4573     cb_backspace=0;
4574     cb_select=0;
4575     undo_history.clear();
4576     undo_history_pos=0;
4577     attr=attributs(14,Xcas_equation_background_color,Xcas_equation_color);
4578     labelsize(14);
4579     modifiable=true;
4580     output_equation=true;
4581     data=Equation_nullstring(attr,0,context0);
4582     Fl_Group::end();
4583     add_scroll_menu();
4584   }
4585 
Equation(int x,int y,int w,int h,const char * l,const gen & g)4586   Equation::Equation(int x, int y, int w, int h, const char* l,const gen & g): Fl_Group(x, y, max(w,20), max(h,20), l){
4587     const giac::context * contextptr = get_context(this);
4588     xleft=0;
4589     ytop=h;
4590     xcur=0;
4591     ycur=0;
4592     begin_sel=-1;
4593     end_sel=-1;
4594     cb_escape=0;
4595     cb_enter=0;
4596     cb_backspace=0;
4597     cb_select=0;
4598     undo_history.clear();
4599     undo_history_pos=0;
4600     attr=attributs(14,Xcas_equation_background_color,Xcas_equation_color);
4601     labelsize(14);
4602     modifiable=true;
4603     output_equation=true;
4604     if (taille(g,max_prettyprint_equation)<max_prettyprint_equation)
4605       data=Equation_compute_size(g,attr,w,contextptr);
4606     else
4607       data=Equation_compute_size(string2gen("Object_too_large",false),attr,w,contextptr);
4608     Fl_Group::end();
4609     add_scroll_menu();
4610   }
4611 
Equation(int x,int y,int w,int h,const char * l,const gen & g,attributs myattr)4612   Equation::Equation(int x, int y, int w, int h, const char* l,const gen & g,attributs myattr) : Fl_Group(x, y, max(w,20), max(h,20), l){
4613     const giac::context * contextptr = get_context(this);
4614     labelsize(giacmin(giacmax(myattr.fontsize,10),16));
4615     xleft=0;
4616     ytop=h;
4617     xcur=0;
4618     ycur=0;
4619     begin_sel=-1;
4620     end_sel=-1;
4621     cb_escape=0;
4622     cb_enter=0;
4623     cb_backspace=0;
4624     cb_select=0;
4625     undo_history.clear();
4626     undo_history_pos=0;
4627     attr=myattr;
4628     modifiable=true;
4629     output_equation=true;
4630     if (taille(g,max_prettyprint_equation)<max_prettyprint_equation)
4631       data=Equation_compute_size(g,attr,w,contextptr);
4632     else
4633       data=Equation_compute_size(string2gen("Object_too_large",false),attr,w,contextptr);
4634     Fl_Group::end();
4635     add_scroll_menu();
4636   }
4637 
Equation(int x,int y,int w,int h,const char * l,const gen & g,attributs myattr,GIAC_CONTEXT)4638   Equation::Equation(int x, int y, int w, int h, const char* l,const gen & g,attributs myattr,GIAC_CONTEXT) : Fl_Group(x, y, max(w,20), max(h,20), l){
4639     labelsize(giacmin(giacmax(myattr.fontsize,10),16));
4640     xleft=0;
4641     ytop=h;
4642     xcur=0;
4643     ycur=0;
4644     begin_sel=-1;
4645     end_sel=-1;
4646     cb_escape=0;
4647     cb_enter=0;
4648     cb_backspace=0;
4649     cb_select=0;
4650     undo_history.clear();
4651     undo_history_pos=0;
4652     attr=myattr;
4653     modifiable=true;
4654     output_equation=true;
4655     if (taille(g,max_prettyprint_equation)<max_prettyprint_equation)
4656       data=Equation_compute_size(g,attr,w,contextptr);
4657     else
4658       data=Equation_compute_size(string2gen("Object_too_large",false),attr,w,contextptr);
4659     Fl_Group::end();
4660     add_scroll_menu();
4661   }
4662 
resize(int x,int y,int w,int h)4663   void Equation::resize(int x, int y, int w, int h){
4664     Fl_Widget::resize(x,y,w,h);
4665     int L=giac::giacmin(20,labelsize());
4666     vscroll->resize(x+Fl_Group::w()-L,y,L,Fl_Group::h()-L);
4667     hscroll->resize(x,y+Fl_Group::h()-L,Fl_Group::w()-2*L,L);
4668     menubar->resize(hscroll->x()+hscroll->w(),hscroll->y(),2*L,L);
4669     setscroll();
4670   }
4671 
~Equation()4672   Equation::~Equation(){
4673     if (Xcas_input_focus==this)
4674       Xcas_input_focus=0;
4675     remove(hscroll);
4676     remove(vscroll);
4677     remove(menubar);
4678     delete vscroll;
4679     delete hscroll;
4680     delete [] menubar->menu();
4681     delete menubar;
4682   }
4683 
4684   // return a variable from the list of vars
select_user_var(int dx,int dy,gen & ans,GIAC_CONTEXT)4685   bool select_user_var(int dx,int dy,gen & ans,GIAC_CONTEXT){
4686     gen res=_VARS(1,contextptr);
4687     if (res.type!=_VECT)
4688       return false;
4689     vecteur v(*res._VECTptr);
4690     int s=v.size();
4691     Fl_Group::current(0);
4692     Fl_Window * w = new Fl_Window(dx,dy);
4693     Fl_Return_Button * button0 = new Fl_Return_Button(2,2,dx/2-4,16);
4694     button0->shortcut(0xff0d);
4695     button0->label(gettext("OK"));
4696     Fl_Button * button1 = new Fl_Button(dx/2+2,2,dx/2-4,16);
4697     button1->shortcut(0xff1b);
4698     button1->label(gettext("Cancel"));
4699     Fl_Browser * browser = new Fl_Browser(2,20,dx,dy-22);
4700     browser->type(2);
4701     browser->label("Variables");
4702     // browser->callback((Fl_Callback*)cb_eqw_browser);
4703     for (int k=0;k<s;++k)
4704       browser->add(v[k].print(contextptr).c_str());
4705     browser->value(1);
4706     int i=1,r=0;
4707     w->end();
4708     w->resizable(w);
4709     w->set_modal();
4710     if (s){
4711       browser->value(1);
4712       w->show();
4713       Fl_Widget * savefocus=Fl::focus();
4714       Fl::focus(button1);
4715       for (;;) {
4716 	Fl_Widget *o = Fl::readqueue();
4717 	if (!o) Fl::wait();
4718 	else {
4719 	  if (o == button0) {r = 0; break;}
4720 	  if (o == button1) {r = 1; break;}
4721 	  if (o == w) { r=0; break; }
4722 	}
4723       }
4724       Fl::focus(savefocus);
4725       w->hide();
4726       i=browser->value();
4727     }
4728     delete browser;
4729     delete button1;
4730     delete button0;
4731     delete w;
4732     if (r==0 && i<=s && i>0){
4733       ans=v[i-1];
4734       return true;
4735     }
4736     else
4737       return false;
4738   }
4739 
Equation_Scrollbar(int x,int y,int w,int h,Equation * ptr,bool is_vertical)4740     Equation_Scrollbar::Equation_Scrollbar(int x,int y,int w,int h,Equation * ptr,bool is_vertical):Fl_Scrollbar(x,y,w,h),eqwptr(ptr),vertical(is_vertical) {
4741       Fl_Scrollbar * o= this;
4742       o->maximum(1000);
4743       o->step(10);
4744       o->slider_size(1);
4745       o->callback( (Fl_Callback*) Equation_cb_scroll );
4746       if (is_vertical)
4747 	o->type(FL_VERTICAL);
4748       else
4749 	o->type(FL_HORIZONTAL);
4750       o->labelsize(giac::giacmin(20,ptr->labelsize()));
4751     };
4752 
4753 #ifndef NO_NAMESPACE_XCAS
4754 } // namespace xcas
4755 #endif // ndef NO_NAMESPACE_XCAS
4756 
4757 #endif // HAVE_LIBFLTK
4758