1 // -*- mode:C++ ; compile-command: "g++ -DHAVE_CONFIG_H -I. -I.. -I../include -I../../giac/include -g -c Graph.cc -DHAVE_CONFIG_H -DIN_GIAC" -*-
2 #include "Graph.h"
3 /*
4  *  Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #ifdef HAVE_LIBFLTK
25 #include <FL/fl_ask.H>
26 #include <FL/fl_ask.H>
27 #include <FL/Fl.H>
28 #include <FL/Fl_Value_Input.H>
29 #include <FL/Fl_Return_Button.H>
30 #include <FL/Fl_Check_Button.H>
31 #include <FL/fl_show_colormap.H>
32 #include <FL/Fl_Tiled_Image.H>
33 #include <FL/Fl_Image.H>
34 #include <FL/Fl_Shared_Image.H>
35 #include <fstream>
36 #include "vector.h"
37 #include <algorithm>
38 #include <fcntl.h>
39 #include <cmath>
40 #include <time.h> // for nanosleep
41 #include <stdio.h>
42 #include <dirent.h>
43 #include <sys/stat.h> // auto-recovery function
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47 #include "path.h"
48 #ifndef IN_GIAC
49 #include <giac/plot.h>
50 #else
51 #include "plot.h"
52 #endif
53 #include "Equation.h"
54 #include "Editeur.h"
55 #include "Xcas1.h"
56 #include "Print.h"
57 #include "Graph3d.h"
58 #include <FL/gl.h>
59 #include "Tableur.h"
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 using namespace std;
65 using namespace giac;
66 
67 
68 #ifndef NO_NAMESPACE_XCAS
69 namespace xcas {
70 #endif // ndef NO_NAMESPACE_XCAS
71 
72   bool do_helpon=true;
73 
74   std::map<std::string,std::pair<Fl_Image *,Fl_Image *> *> texture2d_cache;
75 
pow10(double d)76   static double pow10(double d){
77     return std::pow(10.,d);
78   }
79 
get_texture2d(const string & s,std::pair<Fl_Image *,Fl_Image * > * & texture)80   void get_texture2d(const string & s,std::pair<Fl_Image *,Fl_Image *> * & texture){
81     texture=0;
82     std::map<std::string,std::pair<Fl_Image *,Fl_Image*> *>::const_iterator it,itend=texture2d_cache.end();
83     it=texture2d_cache.find(s);
84     if (it!=itend){
85       texture=it->second;
86       // texture->uncache();
87     }
88     else {
89       Fl_Shared_Image * ptr =Fl_Shared_Image::get(s.c_str());
90       if (ptr)
91 	ptr->reload();
92       texture=new std::pair<Fl_Image *,Fl_Image*>(ptr,0);
93       texture2d_cache[s]=texture;
94     }
95   }
96 
xcas_color(int color,bool dim3)97   void xcas_color(int color,bool dim3){
98     if (color>=0x100 && color<0x17e){
99       int r,g,b;
100       arc_en_ciel(color-(0x100),r,g,b);
101 #ifdef HAVE_LIBFLTK_GL
102       if (dim3)
103 	glColor3f(r/255.,g/255.,b/255.);
104       else
105 #endif
106 	fl_color(r,g,b);
107     }
108     else {
109       if (color>=512){
110 	int r=8*((color>>11)&0x1f);
111 	int g=4*((color>>5) &0x3f);
112 	int b=8*(color & 0x1f);
113 #ifdef HAVE_LIBFLTK_GL
114 	if (dim3)
115 	  glColor3f(r/255.,g/255.,b/255.);
116 	else
117 #endif
118 	  fl_color(r,g,b);
119       }
120       else  {
121 	if (dim3)
122 	  gl_color(color);
123 	else
124 	  fl_color(color);
125       }
126     }
127   }
128 
129   vector<Graph2d3d *> animations;
130 
Min(int i,int j)131   inline int Min(int i,int j) {return i>j?j:i;}
132 
Max(int i,int j)133   inline int Max(int i,int j) {return i>j?i:j;}
134 
quaternion_double(double theta_x,double theta_y,double theta_z)135   quaternion_double::quaternion_double(double theta_x,double theta_y,double theta_z) {
136     *this=euler_deg_to_quaternion_double(theta_x,theta_y,theta_z);
137   }
138 
euler_deg_to_quaternion_double(double a,double b,double c)139   quaternion_double euler_deg_to_quaternion_double(double a,double b,double c){
140     double phi=a*M_PI/180, theta=b*M_PI/180, psi=c*M_PI/180;
141     double c1 = std::cos(phi/2);
142     double s1 = std::sin(phi/2);
143     double c2 = std::cos(theta/2);
144     double s2 = std::sin(theta/2);
145     double c3 = std::cos(psi/2);
146     double s3 = std::sin(psi/2);
147     double c1c2 = c1*c2;
148     double s1s2 = s1*s2;
149     double w =c1c2*c3 - s1s2*s3;
150     double x =c1c2*s3 + s1s2*c3;
151     double y =s1*c2*c3 + c1*s2*s3;
152     double z =c1*s2*c3 - s1*c2*s3;
153     return quaternion_double(w,x,y,z);
154   }
155 
quaternion_double_to_euler_deg(const quaternion_double & q,double & phi,double & theta,double & psi)156   void quaternion_double_to_euler_deg(const quaternion_double & q,double & phi,double & theta, double & psi){
157     double test = q.x*q.y + q.z*q.w;
158     if (test > 0.499) { // singularity at north pole
159       phi = 2 * atan2(q.x,q.w) * 180/M_PI;
160       theta = 90;
161       psi = 0;
162       return;
163     }
164     if (test < -0.499) { // singularity at south pole
165       phi = -2 * atan2(q.x,q.w) * 180/M_PI;
166       theta = - 90;
167       psi = 0;
168       return;
169     }
170     double sqx = q.x*q.x;
171     double sqy = q.y*q.y;
172     double sqz = q.z*q.z;
173     phi = atan2(2*q.y*q.w-2*q.x*q.z , 1 - 2*sqy - 2*sqz) * 180/M_PI;
174     theta = asin(2*test) * 180/M_PI;
175     psi = atan2(2*q.x*q.w-2*q.y*q.z , 1 - 2*sqx - 2*sqz) * 180/M_PI;
176   }
177 
operator *(const quaternion_double & q1,const quaternion_double & q2)178   quaternion_double operator * (const quaternion_double & q1,const quaternion_double & q2){
179     double z=q1.w*q2.z+q2.w*q1.z+q1.x*q2.y-q2.x*q1.y;
180     double x=q1.w*q2.x+q2.w*q1.x+q1.y*q2.z-q2.y*q1.z;
181     double y=q1.w*q2.y+q2.w*q1.y+q1.z*q2.x-q2.z*q1.x;
182     double w=q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z;
183     return quaternion_double(w,x,y,z);
184   }
185 
186   // q must be a unit
get_axis_angle_deg(const quaternion_double & q,double & x,double & y,double & z,double & theta)187   void get_axis_angle_deg(const quaternion_double & q,double &x,double &y,double & z, double &theta){
188     double scale=1-q.w*q.w;
189     if (scale>1e-6){
190       scale=std::sqrt(scale);
191       theta=2*std::acos(q.w)*180/M_PI;
192       x=q.x/scale;
193       y=q.y/scale;
194       z=q.z/scale;
195     }
196     else {
197       x=0; y=0; z=1;
198       theta=0;
199     }
200   }
201 
operator <<(ostream & os,const quaternion_double & q)202   ostream & operator << (ostream & os,const quaternion_double & q){
203     return os << q.w << "+" << q.x << "i+" << q.y << "j+" << q.z << "k";
204   }
205 
readrgb(const string & s,int W,int H,gen & res)206   bool readrgb(const string & s,int W,int H,gen & res){
207     Fl_Image * image=Fl_Shared_Image::get(s.c_str());
208     if (image && W && H)
209       image=image->copy(W,H);
210     if (!image || image->count()!=1)
211       return false;
212     const char * data = image->data()[0];
213     unsigned ih=image->h(),iw=image->w(),id=image->d();
214     gen tmpr=vecteur(ih),tmpg=vecteur(ih),tmpb=vecteur(ih),tmpa=vecteur(ih);
215     // alpha is returned before blue because red==1, green==2, blue==4
216     res=gen(makevecteur(makevecteur(4,int(ih),int(iw)),tmpr,tmpg,tmpa,tmpb),_RGBA__VECT);
217     vecteur & vr=*tmpr._VECTptr;
218     vecteur & vg=*tmpg._VECTptr;
219     vecteur & vb=*tmpb._VECTptr;
220     vecteur & va=*tmpa._VECTptr;
221     unsigned l=0;
222     for (unsigned i=0;i<ih;++i){
223       if (debug_infolevel)
224 	cerr << "readrgb, reading row " << i << '\n';
225       vr[i]=vecteur(iw);
226       vg[i]=vecteur(iw);
227       vb[i]=vecteur(iw);
228       va[i]=vecteur(iw,255);
229       vecteur & wr = *vr[i]._VECTptr;
230       vecteur & wg = *vg[i]._VECTptr;
231       vecteur & wb = *vb[i]._VECTptr;
232       vecteur & wa = *va[i]._VECTptr;
233       for (unsigned j=0;j<iw;++j){
234 	for (unsigned k=0;k<id;++k,++l){
235 	  unsigned u=data[l] & 0xff;
236 	  switch(k){
237 	  case 0:
238 	    wr[j]=int(u);
239 	    break;
240 	  case 1:
241 	    wg[j]=int(u);
242 	    break;
243 	  case 2:
244 	    wb[j]=int(u);
245 	    break;
246 	  case 3:
247 	    wa[j]=int(u);
248 	    break;
249 	  }
250 	}
251       }
252     }
253     return true;
254   }
255 
objet_bidon()256   objet_bidon::objet_bidon(){
257     // localization code and pointer to RGB image reader
258     if (!giac::readrgb_ptr){
259       giac::readrgb_ptr=readrgb;
260 #ifdef HAVE_LC_MESSAGES
261       xcas_locale()=getenv("XCAS_LOCALE")?getenv("XCAS_LOCALE"):giac_locale_location;
262       cerr << "// Using locale " << xcas_locale() << '\n';
263       const char * ptr=setlocale (LC_MESSAGES, "");
264       if (ptr)
265 	cerr << "// " << ptr << '\n';
266       else
267 	cerr << "// setlocale returns 0" << '\n';
268 #if defined(HAVE_GETTEXT)
269       cerr << "// " << bindtextdomain (PACKAGE, xcas_locale().c_str()) << '\n';
270       cerr << "// " << textdomain (PACKAGE) << '\n';
271       cerr << "// " << bind_textdomain_codeset (PACKAGE, "UTF-8") << '\n';
272 #endif
273 #endif
274     }
275   };
276 
xcas_locale()277   std::string & xcas_locale(){
278     static string * ans = new string;
279     return * ans;
280   }
281   objet_bidon mon_objet_bidon;
282   // objet_bidon * mon_objet_bidon_ptr=new objet_bidon;
283 
284   // New buttons/menus:
285   // row1: z+   up_y  up_z
286   // row2: left ortho right
287   // row3: z-   down  down_z
288   // row4: back forw  cfg_menu
cb_graph_buttons(Fl_Widget * b,void *)289   void cb_graph_buttons(Fl_Widget * b,void *){
290     Fl_Group * g = b->parent();
291     if (!g) return;
292     int i=g->find(b); // position of button inside group of buttons
293     g = g->parent(); // should be mouse_param_group
294     if (!g) return;
295     if (Mouse_Position * mp=dynamic_cast<Mouse_Position *>(g->child(0))){
296       Graph3d * g3=dynamic_cast<Graph3d *>(mp->graphic);
297       double dh=(mp->graphic->window_ymax-mp->graphic->window_ymin)/10;
298       double dw=(mp->graphic->window_xmax-mp->graphic->window_xmin)/10;
299       double dz=(mp->graphic->window_zmax-mp->graphic->window_zmin)/10;
300       switch (i){
301       case 0:
302 	mp->graphic->zoom(0.707);
303 	break;
304       case 1:
305 	mp->graphic->up(dh);
306 	break;
307       case 2:
308 	if (g3)
309 	  mp->graphic->up_z(dz);
310 	else {
311 	  mp->graphic->zoomy(0.707);
312 	  mp->graphic->push_cfg();
313 	}
314 	break;
315       case 3:
316 	mp->graphic->left(dw);
317 	break;
318       case 4:
319 	if (g3){
320 	  g3->below_depth_hidden=!g3->below_depth_hidden;
321 	  g3->redraw();
322 	}
323 	else
324 	  mp->graphic->orthonormalize();
325 	break;
326       case 5:
327 	mp->graphic->right(dw);
328 	break;
329       case 6:
330 	mp->graphic->zoom(1.414);
331 	break;
332       case 7:
333 	mp->graphic->down(dh);
334 	break;
335       case 8:
336 	if (g3)
337 	  mp->graphic->down_z(dz);
338 	else {
339 	  mp->graphic->zoomy(1.414);
340 	  mp->graphic->push_cfg();
341 	}
342 	break;
343       case 9:
344 	mp->graphic->move_cfg(-1);
345 	break;
346       case 10:
347 	mp->graphic->move_cfg(1);
348 	break;
349       case 11:
350 	mp->graphic->config();
351 	break;
352       case 12:
353 	mp->graphic->paused=!mp->graphic->paused;
354 	break;
355       case 13:
356 	mp->graphic->autoscale(false);
357 	break;
358       }
359       if (Fl_Widget * g=dynamic_cast<Graph2d *>(mp->graphic))
360 	g->redraw();
361     }
362   }
363 
update_infos(const gen & g,GIAC_CONTEXT)364   void Graph2d3d::update_infos(const gen & g,GIAC_CONTEXT){
365     if (g.type==_VECT && g.subtype==_GRAPH__VECT){
366       show_axes=false;
367       orthonormalize();
368     }
369     if (g.is_symb_of_sommet(at_equal)){
370       // detect a title or a x/y-axis name
371       gen & f = g._SYMBptr->feuille;
372       if (f.type==_VECT && f._VECTptr->size()==2){
373 	gen & optname = f._VECTptr->front();
374 	gen & optvalue= f._VECTptr->back();
375 	if (optname==at_legende && optvalue.type==_VECT){
376 	  vecteur & optv=(*optvalue._VECTptr);
377 	  int optvs=optv.size();
378 	  if (optvs>=1)
379 	    x_axis_unit=printstring(optv[0],contextptr);
380 	  if (optvs>=2)
381 	    y_axis_unit=printstring(optv[1],contextptr);
382 	  if (optvs>=3)
383 	    z_axis_unit=printstring(optv[2],contextptr);
384 	}
385 	if (optname.type==_INT_ && optname.subtype == _INT_PLOT){
386 	  if (optname.val==_GL_TEXTURE){
387 	    if (optvalue.type==_VECT && optvalue._VECTptr->size()==2 && optvalue._VECTptr->front().type==_STRNG && is_undef(optvalue._VECTptr->back())){
388 	      // reload cached image
389 	      optvalue=optvalue._VECTptr->front();
390 	      std::map<std::string,std::pair<Fl_Image *,Fl_Image*> *>::iterator it,itend=texture2d_cache.end();
391 	      it=texture2d_cache.find(optvalue._STRNGptr->c_str());
392 	      if (it!=itend){
393 		std::pair<Fl_Image *,Fl_Image*> * old= it->second;
394 		delete old;
395 		texture2d_cache.erase(it);
396 	      }
397 	      get_texture2d(*optvalue._STRNGptr,background_image);
398 	    }
399 	    else {
400 	      if (optvalue.type==_STRNG){
401 		get_texture2d(*optvalue._STRNGptr,background_image);
402 	      }
403 	      else {
404 		background_image=0;
405 	      }
406 	    }
407 	  }
408 	  if (optname.val==_TITLE )
409 	    title=printstring(optvalue,contextptr);
410 	  if (optname.val==_AXES){
411 	    if (optvalue.type==_INT_)
412 	      show_axes=optvalue.val;
413 	  }
414 	  if (optname.val==_LABELS && optvalue.type==_VECT){
415 	    vecteur & optv=(*optvalue._VECTptr);
416 	    int optvs=optv.size();
417 	    if (optvs>=1)
418 	      x_axis_name=printstring(optv[0],contextptr);
419 	    if (optvs>=2)
420 	      y_axis_name=printstring(optv[1],contextptr);
421 	    if (optvs>=3)
422 	      z_axis_name=printstring(optv[2],contextptr);
423 	  }
424 	  if (optname.val==_GL_ORTHO && optvalue==1)
425 	    orthonormalize();
426 	  if (optname.val==_GL_X_AXIS_COLOR && optvalue.type==_INT_)
427 	    x_axis_color=optvalue.val;
428 	  if (optname.val==_GL_Y_AXIS_COLOR && optvalue.type==_INT_)
429 	    y_axis_color=optvalue.val;
430 	  if (optname.val==_GL_Z_AXIS_COLOR && optvalue.type==_INT_)
431 	    z_axis_color=optvalue.val;
432 	  if (optname.val>=_GL_X && optname.val<=_GL_Z && optvalue.is_symb_of_sommet(at_interval)){
433 	    gen optvf=evalf_double(optvalue._SYMBptr->feuille,1,contextptr);
434 	    if (optvf.type==_VECT && optvf._VECTptr->size()==2){
435 	      gen a=optvf._VECTptr->front();
436 	      gen b=optvf._VECTptr->back();
437 	      if (a.type==_DOUBLE_ && b.type==_DOUBLE_){
438 		switch (optname.val){
439 		case _GL_X:
440 		  window_xmin=a._DOUBLE_val;
441 		  window_xmax=b._DOUBLE_val;
442 		  break;
443 		case _GL_Y:
444 		  window_ymin=a._DOUBLE_val;
445 		  window_ymax=b._DOUBLE_val;
446 		  break;
447 		case _GL_Z:
448 		  window_zmin=a._DOUBLE_val;
449 		  window_zmax=b._DOUBLE_val;
450 		  break;
451 		}
452 	      }
453 	    }
454 	  }
455 	  gen optvalf=evalf_double(optvalue,1,contextptr);
456 	  if (optname.val==_GL_XTICK && optvalf.type==_DOUBLE_)
457 	    x_tick=optvalf._DOUBLE_val;
458 	  if (optname.val==_GL_YTICK && optvalf.type==_DOUBLE_)
459 	    y_tick=optvalf._DOUBLE_val;
460 	  if (optname.val==_GL_ZTICK && optvalf.type==_DOUBLE_)
461 	    z_tick=optvalf._DOUBLE_val;
462 	  if (optname.val==_GL_ANIMATE && optvalf.type==_DOUBLE_)
463 	    animation_dt=optvalf._DOUBLE_val;
464 	  if (optname.val==_GL_SHOWAXES && optvalue.type==_INT_)
465 	    show_axes=optvalue.val;
466 	  if (optname.val==_GL_SHOWNAMES && optvalue.type==_INT_)
467 	    show_names=optvalue.val;
468 	  if (optname.val>=_GL_X_AXIS_NAME && optname.val<=_GL_Z_AXIS_UNIT && optvalue.type==_STRNG){
469 	    if (optname.val==_GL_X_AXIS_NAME) x_axis_name=*optvalue._STRNGptr;
470 	    if (optname.val==_GL_Y_AXIS_NAME) y_axis_name=*optvalue._STRNGptr;
471 	    if (optname.val==_GL_Z_AXIS_NAME) z_axis_name=*optvalue._STRNGptr;
472 	    if (optname.val==_GL_X_AXIS_UNIT) x_axis_unit=*optvalue._STRNGptr;
473 	    if (optname.val==_GL_Y_AXIS_UNIT) y_axis_unit=*optvalue._STRNGptr;
474 	    if (optname.val==_GL_Z_AXIS_UNIT) z_axis_unit=*optvalue._STRNGptr;
475 	  }
476 	  if (optname.val==_GL_QUATERNION && optvalf.type==_VECT && optvalf._VECTptr->size()==4){
477 	    vecteur & optvalv=*optvalf._VECTptr;
478 	    if (optvalv[0].type==_DOUBLE_ && optvalv[1].type==_DOUBLE_ &&
479 		optvalv[2].type==_DOUBLE_ && optvalv[3].type==_DOUBLE_){
480 	      q.x=optvalv[0]._DOUBLE_val;
481 	      q.y=optvalv[1]._DOUBLE_val;
482 	      q.z=optvalv[2]._DOUBLE_val;
483 	      q.w=optvalv[3]._DOUBLE_val;
484 	    }
485 	  }
486 	  if (optname.val==_GL_LOGX && optvalue.type==_INT_){
487 	    display_mode &= (0xffff ^ 0x400);
488 	    if (optvalue.val)
489 	      display_mode |= 0x400;
490 	  }
491 	  if (optname.val==_GL_LOGY && optvalue.type==_INT_){
492 	    display_mode &= (0xffff ^ 0x800);
493 	    if (optvalue.val)
494 	      display_mode |= 0x800;
495 	  }
496 	  if (optname.val==_GL_LOGZ && optvalue.type==_INT_){
497 	    display_mode &= (0xffff ^ 0x1000);
498 	    if (optvalue.val)
499 	      display_mode |= 0x1000;
500 	  }
501 	  if (dynamic_cast<Graph3d *>(this)){
502 	    if (optname.val==_GL_ROTATION_AXIS && optvalf.type==_VECT && optvalf._VECTptr->size()==3){
503 	      vecteur & optvalv=*optvalf._VECTptr;
504 	      if (optvalv[0].type==_DOUBLE_ && optvalv[1].type==_DOUBLE_ &&
505 		  optvalv[2].type==_DOUBLE_ ){
506 		rotanim_rx=optvalv[0]._DOUBLE_val;
507 		rotanim_ry=optvalv[1]._DOUBLE_val;
508 		rotanim_rz=optvalv[2]._DOUBLE_val;
509 	      }
510 	    }
511 	    if (optname.val==_GL_FLAT && optvalue.type==_INT_){
512 	      display_mode &= (0xffff ^ 0x10);
513 	      if (optvalue.val)
514 		display_mode |= 0x10;
515 	    }
516 	    if (optname.val==_GL_LIGHT && optvalue.type==_INT_){
517 	      display_mode &= (0xffff ^ 0x8);
518 	      if (optvalue.val)
519 		display_mode |= 0x8;
520 	    }
521 	    if (optname.val==_GL_PERSPECTIVE && optvalue.type==_INT_){
522 	      display_mode &= (0xffff ^ 0x4);
523 	      if (!optvalue.val)
524 		display_mode |= 0x4;
525 	    }
526 	    // GL_LIGHT_MODEL_COLOR_CONTROL=GL_SEPARATE_SPECULAR_COLOR ||  GL_SINGLE_COLOR
527 #ifndef WIN32
528 	    if (optname.val==_GL_LIGHT_MODEL_COLOR_CONTROL && optvalue.type==_INT_)
529 	      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,optvalue.val);
530 	    /* GL_LIGHT_MODEL_LOCAL_VIEWER=floating-point value that spec-
531 	       ifies how specular reflection angles are computed.  If params
532 	       is 0 (or 0.0),  specular  reflection  angles  take  the  view
533 	       direction  to  be  parallel to and in the direction of the -z
534 	       axis, regardless of the location of the vertex in eye coordi-
535 	       nates.  Otherwise, specular reflections are computed from the
536 	       origin of the eye coordinate system.  The initial value is 0. */
537 	    if (optname.val==_GL_LIGHT_MODEL_LOCAL_VIEWER){
538 	      if (optvalf.type==_DOUBLE_)
539 		glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER,optvalf._DOUBLE_val);
540 	    }
541 #endif
542 #ifdef HAVE_LIBFLTK_GL
543 	    /* GL_LIGHT_MODEL_TWO_SIDE = true /false */
544 	    if (optname.val==_GL_LIGHT_MODEL_TWO_SIDE && optvalue.type==_INT_){
545 	      glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,optvalue.val);
546 	    }
547 	    /* GL_LIGHT_MODEL_AMBIENT=[r,g,b,a] */
548 	    if (optname.val==_GL_LIGHT_MODEL_AMBIENT && optvalf.type==_VECT && optvalf._VECTptr->size()==4){
549 	      vecteur & w=*optvalf._VECTptr;
550 	      GLfloat tab[4]={(GLfloat)w[0]._DOUBLE_val,(GLfloat)w[1]._DOUBLE_val,(GLfloat)w[2]._DOUBLE_val,(GLfloat)w[3]._DOUBLE_val};
551 	      glLightModelfv(GL_LIGHT_MODEL_AMBIENT,tab);
552 	    }
553 	    // gl_blend=[d,s]
554 	    // habituellement gl_blend=[gl_src_alpha,gl_one_minus_src_alpha]
555 	    if (optname.val==_GL_BLEND){
556 	      if (is_zero(optvalue)){
557 		glDisable(GL_BLEND);
558 		glEnable(GL_DEPTH_TEST);
559 	      }
560 	      else {
561 		glDisable(GL_DEPTH_TEST);
562 		glEnable(GL_BLEND);
563 		if (optvalue.type==_VECT && optvalue._VECTptr->size()==2)
564 		  glBlendFunc(optvalue._VECTptr->front().val,optvalue._VECTptr->back().val);
565 		if (is_minus_one(optvalue))
566 		  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
567 	      }
568 	    }
569 #endif
570 	    // gl_light0=[option1=value1,...]
571 	    if (optname.val>=_GL_LIGHT0 && optname.val<=_GL_LIGHT7 && optvalue.type==_VECT){
572 	      int j=optname.val-_GL_LIGHT0;
573 	      // reset light0+j
574 	      light_x[j]=0;light_y[j]=0;light_z[j]=0;light_w[j]=1;
575 	      float di=j?0:1;
576 	      light_diffuse_r[j]=di;light_diffuse_g[j]=di;light_diffuse_b[j]=di;light_diffuse_a[j]=di;
577 	      light_specular_r[j]=di;light_specular_g[j]=di;light_specular_b[j]=di;light_specular_a[j]=di;
578 	      light_ambient_r[j]=0;light_ambient_g[j]=0;light_ambient_b[j]=0;light_ambient_a[j]=1;
579 	      light_spot_x[j]=0;light_spot_y[j]=0;light_spot_z[j]=-1;light_spot_w[j]=0;
580 	      light_spot_exponent[j]=0;light_spot_cutoff[j]=180;
581 	      light_0[j]=1;light_1[j]=0;light_2[j]=0;
582 	      vecteur & optv=*optvalue._VECTptr;
583 	      for (unsigned i=0;i<optv.size();++i){
584 		gen & optg = optv[i];
585 		if ( (optg.is_symb_of_sommet(at_equal) || optg.is_symb_of_sommet(at_same) )  && optg._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){
586 		  gen & optgname = optg._SYMBptr->feuille._VECTptr->front();
587 		  gen optgval = evalf_double(optg._SYMBptr->feuille._VECTptr->back(),1,contextptr);
588 		  bool vect4=optgval.type==_VECT && optgval._VECTptr->size()==4;
589 		  vecteur xyzw;
590 		  if (vect4)
591 		    xyzw=*optgval._VECTptr;
592 		  switch (optgname.val){
593 		  case _GL_AMBIENT:
594 		    light_ambient_r[j]=xyzw[0]._DOUBLE_val;
595 		    light_ambient_g[j]=xyzw[1]._DOUBLE_val;
596 		    light_ambient_b[j]=xyzw[2]._DOUBLE_val;
597 		    light_ambient_a[j]=xyzw[3]._DOUBLE_val;
598 		    break;
599 		  case _GL_SPECULAR:
600 		    light_specular_r[j]=xyzw[0]._DOUBLE_val;
601 		    light_specular_g[j]=xyzw[1]._DOUBLE_val;
602 		    light_specular_b[j]=xyzw[2]._DOUBLE_val;
603 		    light_specular_a[j]=xyzw[3]._DOUBLE_val;
604 		    break;
605 		  case _GL_DIFFUSE:
606 		    light_diffuse_r[j]=xyzw[0]._DOUBLE_val;
607 		    light_diffuse_g[j]=xyzw[1]._DOUBLE_val;
608 		    light_diffuse_b[j]=xyzw[2]._DOUBLE_val;
609 		    light_diffuse_a[j]=xyzw[3]._DOUBLE_val;
610 		    break;
611 		  case _GL_POSITION:
612 		    light_x[j]=xyzw[0]._DOUBLE_val;
613 		    light_y[j]=xyzw[1]._DOUBLE_val;
614 		    light_z[j]=xyzw[2]._DOUBLE_val;
615 		    light_w[j]=xyzw[3]._DOUBLE_val;
616 		    break;
617 		  case _GL_SPOT_DIRECTION:
618 		    light_spot_x[j]=xyzw[0]._DOUBLE_val;
619 		    light_spot_y[j]=xyzw[1]._DOUBLE_val;
620 		    light_spot_z[j]=xyzw[2]._DOUBLE_val;
621 		    light_spot_w[j]=xyzw[3]._DOUBLE_val;
622 		    break;
623 		  case _GL_SPOT_EXPONENT:
624 		    light_spot_exponent[j]=optgval._DOUBLE_val;
625 		    break;
626 		  case _GL_SPOT_CUTOFF:
627 		    light_spot_cutoff[j]=optgval._DOUBLE_val;
628 		    break;
629 		  case _GL_CONSTANT_ATTENUATION:
630 		    light_0[j]=optgval._DOUBLE_val;
631 		    break;
632 		  case _GL_LINEAR_ATTENUATION:
633 		    light_1[j]=optgval._DOUBLE_val;
634 		    break;
635 		  case _GL_QUADRATIC_ATTENUATION:
636 		    light_2[j]=optgval._DOUBLE_val;
637 		    break;
638 		  }
639 		}
640 		;
641 	      } // end for i
642 	    }
643 	  } // end opengl options
644 	}
645       }
646     }
647     if (g.type==_VECT){
648       const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
649       for (;it!=itend;++it)
650 	update_infos(*it,contextptr);
651     }
652   }
653 
move_cfg(int i)654   void Graph2d3d::move_cfg(int i){
655     if (history.empty()) return;
656     int j=i+history_pos;
657     int s=history.size();
658     if (j>s) j=s;
659     if (j<1) j=1;
660     history_pos=j;
661     window_xyz & h = history[j-1];
662     window_xmin=h.xmin;
663     window_xmax=h.xmax;
664     window_ymin=h.ymin;
665     window_ymax=h.ymax;
666     window_zmin=h.zmin;
667     window_zmax=h.zmax;
668   }
669 
push_cfg()670   void Graph2d3d::push_cfg(){
671     int s=history.size();
672     if (history_pos<s && history_pos>=0){
673       history.erase(history.begin()+history_pos,history.end());
674     }
675     history.push_back(window_xyz(window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax));
676     history_pos=history.size();
677   }
678 
clear_cfg()679   void Graph2d3d::clear_cfg(){
680     history_pos=0;
681     history.clear();
682   }
683 
find_xyz(double i,double j,double k,double & x,double & y,double & z)684   void Graph2d3d::find_xyz(double i,double j,double k,double &x,double&y,double &z){
685     x=i; y=j; z=k;
686   }
687 
find_xy(double i,double j,double & x,double & y) const688   void Graph2d::find_xy(double i,double j,double & x,double & y) const {
689     x=window_xmin+i*(window_xmax-window_xmin)/(w()-(show_axes?ylegende*labelsize():0));
690     y=window_ymax-j*(window_ymax-window_ymin)/(h()-(show_axes?((title.empty()?1:2)*labelsize()):0));
691   }
692 
find_xyz(double i,double j,double k,double & x,double & y,double & z)693   void Graph2d::find_xyz(double i,double j,double k,double & x,double & y,double & z) {
694     z=k;
695     find_xy(i,j,x,y);
696   }
697 
in_find_graph2d3d(Fl_Widget * wid)698   Graph2d3d * in_find_graph2d3d(Fl_Widget * wid){
699     if (Graph2d3d * g=dynamic_cast<Graph2d3d *>(wid))
700       return g;
701     if (Fl_Group * gr =dynamic_cast<Fl_Group *>(wid)){
702       // search in children
703       int n=gr->children();
704       for (int i=0;i<n;++i){
705 	if (Graph2d3d * res = in_find_graph2d3d(gr->child(i)))
706 	  return res;
707       }
708     }
709     return 0;
710   }
711 
find_graph2d3d(Fl_Widget * wid)712   Graph2d3d * find_graph2d3d(Fl_Widget * wid){
713     if (!wid) return 0;
714     if (Graph2d3d * res = dynamic_cast<Graph2d3d *>(Fl::focus()) )
715       return res;
716     if (Graph2d3d * res=in_find_graph2d3d(wid))
717       return res;
718     return find_graph2d3d(wid->parent());
719   }
720 
cb_Graph2d3d_LaTeX_Preview(Fl_Menu_ * m,void *)721   static void cb_Graph2d3d_LaTeX_Preview(Fl_Menu_* m , void*) {
722     const char * filename=find_graph2d3d(m)->latex(0);
723     if (filename)
724       xdvi(filename);
725   }
726 
cb_Graph2d3d_LaTeX_Print(Fl_Menu_ * m,void *)727   static void cb_Graph2d3d_LaTeX_Print(Fl_Menu_* m , void*) {
728     const char * filename=find_graph2d3d(m)->latex(0);
729     if (filename)
730       dvips(filename);
731   }
732 
cb_Graph2d3d_Print(Fl_Menu_ * m,void *)733   static void cb_Graph2d3d_Print(Fl_Menu_* m , void*) {
734     Graph2d3d * gr = find_graph2d3d(m);
735     if (gr)
736       widget_print(gr);
737   }
738 
cb_Graph2d3d_Preview(Fl_Menu_ * m,void *)739   static void cb_Graph2d3d_Preview(Fl_Menu_* m , void*) {
740     Graph2d3d * gr = find_graph2d3d(m);
741     if (gr)
742       widget_ps_print(gr,gr->title,true);
743   }
744 
cb_Graph3dpng(Fl_Menu_ * m,void *)745   static void cb_Graph3dpng(Fl_Menu_* m , void*) {
746     Graph2d3d * gr = find_graph2d3d(m);
747     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
748       char * filename = file_chooser(gettext("Export to PNG file"),"*.png","session.png");
749       if(!filename) return;
750       gr3->opengl2png(filename);
751     }
752   }
753 
cb_Graph2d3d_Autoscale(Fl_Menu_ * m,void *)754   static void cb_Graph2d3d_Autoscale(Fl_Menu_* m , void*) {
755     Graph2d3d * gr = find_graph2d3d(m);
756     if (gr)
757       gr->autoscale(false);
758   }
759 
cb_Graph2d3d_AutoscaleFull(Fl_Menu_ * m,void *)760   static void cb_Graph2d3d_AutoscaleFull(Fl_Menu_* m , void*) {
761     Graph2d3d * gr = find_graph2d3d(m);
762     if (gr)
763       gr->autoscale(true);
764   }
765 
cb_Graph2d3d_Orthonormalize(Fl_Menu_ * m,void *)766   static void cb_Graph2d3d_Orthonormalize(Fl_Menu_* m , void*) {
767     Graph2d3d * gr = find_graph2d3d(m);
768     if (gr)
769       gr->orthonormalize();
770   }
771 
cb_Graph2d3d_Next(Fl_Menu_ * m,void *)772   static void cb_Graph2d3d_Next(Fl_Menu_* m , void*) {
773     Graph2d3d * gr = find_graph2d3d(m);
774     if (gr)
775       gr->move_cfg(1);
776   }
777 
cb_Graph2d3d_Previous(Fl_Menu_ * m,void *)778   static void cb_Graph2d3d_Previous(Fl_Menu_* m , void*) {
779     Graph2d3d * gr = find_graph2d3d(m);
780     if (gr)
781       gr->move_cfg(-1);
782   }
783 
cb_Graph2d3d_Zoomout(Fl_Menu_ * m,void *)784   static void cb_Graph2d3d_Zoomout(Fl_Menu_* m , void*) {
785     Graph2d3d * gr = find_graph2d3d(m);
786     if (gr)
787       gr->zoom(1.414);
788   }
789 
cb_Graph2d3d_Zoomin(Fl_Menu_ * m,void *)790   static void cb_Graph2d3d_Zoomin(Fl_Menu_* m , void*) {
791     Graph2d3d * gr = find_graph2d3d(m);
792     if (gr)
793       gr->zoom(0.707);
794   }
795 
cb_Graph2d3d_Config(Fl_Menu_ * m,void *)796   static void cb_Graph2d3d_Config(Fl_Menu_* m , void*) {
797     Graph2d3d * gr = find_graph2d3d(m);
798     if (gr)
799       gr->config();
800   }
801 
cb_Graph2d3d_Pause(Fl_Menu_ * m,void *)802   static void cb_Graph2d3d_Pause(Fl_Menu_* m , void*) {
803     Graph2d3d * gr = find_graph2d3d(m);
804     if (gr)
805       gr->paused=true;
806   }
807 
cb_Graph2d3d_Stop(Fl_Menu_ * m,void *)808   static void cb_Graph2d3d_Stop(Fl_Menu_* m , void*) {
809     Graph2d3d * gr = find_graph2d3d(m);
810     if (gr){
811       gr->animation_dt=0;
812       gr->animation_instructions_pos=0;
813     }
814   }
815 
cb_Graph2d3d_Restart(Fl_Menu_ * m,void *)816   static void cb_Graph2d3d_Restart(Fl_Menu_* m , void*) {
817     Graph2d3d * gr = find_graph2d3d(m);
818     if (gr)
819       gr->paused=false;
820   }
821 
cb_Graph2d3d_Faster(Fl_Menu_ * m,void *)822   static void cb_Graph2d3d_Faster(Fl_Menu_* m , void*) {
823     Graph2d3d * gr = find_graph2d3d(m);
824     if (gr){
825       if (gr->animation_dt)
826 	gr->animation_dt /= 2;
827       else
828 	gr->animation_dt = 0.2;
829     }
830   }
831 
cb_Graph2d3d_Slower(Fl_Menu_ * m,void *)832   static void cb_Graph2d3d_Slower(Fl_Menu_* m , void*) {
833     Graph2d3d * gr = find_graph2d3d(m);
834     if (gr){
835       if (gr->animation_dt)
836 	gr->animation_dt *= 2;
837       else
838 	gr->animation_dt = 0.2;
839     }
840   }
841 
cb_Graph2d3d_hide(Fl_Menu_ * m,void *)842   static void cb_Graph2d3d_hide(Fl_Menu_* m , void*) {
843     Graph2d3d * gr = find_graph2d3d(m);
844     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
845       gr3->below_depth_hidden=true;
846       gr3->redraw();
847     }
848   }
849 
cb_Graph2d3d_show(Fl_Menu_ * m,void *)850   static void cb_Graph2d3d_show(Fl_Menu_* m , void*) {
851     Graph2d3d * gr = find_graph2d3d(m);
852     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
853       gr3->below_depth_hidden=false;
854       gr3->redraw();
855     }
856   }
857 
cb_Graph2d3d_startview(Fl_Menu_ * m,void *)858   static void cb_Graph2d3d_startview(Fl_Menu_* m , void*) {
859     Graph2d3d * gr = find_graph2d3d(m);
860     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
861       gr3->theta_x=-13;
862       gr3->theta_y=-95;
863       gr3->theta_z=-110;
864       gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y);
865       gr3->redraw();
866     }
867   }
868 
cb_Graph2d3d_xview(Fl_Menu_ * m,void *)869   static void cb_Graph2d3d_xview(Fl_Menu_* m , void*) {
870     Graph2d3d * gr = find_graph2d3d(m);
871     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
872       gr3->theta_x=0;
873       gr3->theta_y=-90;
874       gr3->theta_z=-90;
875       gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y);
876       gr3->redraw();
877     }
878   }
879 
cb_Graph2d3d_yview(Fl_Menu_ * m,void *)880   static void cb_Graph2d3d_yview(Fl_Menu_* m , void*) {
881     Graph2d3d * gr = find_graph2d3d(m);
882     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
883       gr3->theta_x=0;
884       gr3->theta_y=-90;
885       gr3->theta_z=0;
886       gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y);
887       gr3->redraw();
888     }
889   }
890 
cb_Graph2d3d_zview(Fl_Menu_ * m,void *)891   static void cb_Graph2d3d_zview(Fl_Menu_* m , void*) {
892     Graph2d3d * gr = find_graph2d3d(m);
893     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
894       gr3->theta_x=0;
895       gr3->theta_y=0;
896       gr3->theta_z=0;
897       gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y);
898       gr3->redraw();
899     }
900   }
901 
cb_Graph2d3d_mouse_plan(Fl_Menu_ * m,void *)902   static void cb_Graph2d3d_mouse_plan(Fl_Menu_* m , void*) {
903     if (!Fl::focus())
904       return;
905     Graph2d3d * gr = find_graph2d3d(m);
906     if (Graph3d * gr3d = dynamic_cast<Graph3d *>(gr)){
907       double a,b,c;
908       gr3d->current_normal(a,b,c);
909       gr3d->normal2plan(a,b,c); // divides a,b,c by dx^2,...
910       double x0,y0,z0,t0;
911       gr3d->find_xyz(gr3d->x()+gr3d->w()/2,gr3d->y()+gr3d->h()/2,gr3d->depth,x0,y0,z0);
912       t0=a*x0+b*y0+c*z0;
913       if (std::abs(t0)<std::abs(gr3d->window_zmax-gr3d->window_zmin)/1000)
914 	t0=0;
915       string s="plan("+print_DOUBLE_(a)+"*x+"+print_DOUBLE_(b)+"*y+"+print_DOUBLE_(c)+"*z="+print_DOUBLE_(t0)+")";
916       in_Xcas_input_char(Fl::focus(),s,' ');
917     }
918   }
919 
920   // image of (x,y,z) by rotation around axis r(rx,ry,rz) of angle theta
rotate(double rx,double ry,double rz,double theta,double x,double y,double z,double & X,double & Y,double & Z)921   void rotate(double rx,double ry,double rz,double theta,double x,double y,double z,double & X,double & Y,double & Z){
922     /*
923     quaternion_double q=rotation_2_quaternion_double(rx,ry,rz,theta);
924     quaternion_double qx(x,y,z,0);
925     quaternion_double qX=conj(q)*qx*q;
926     */
927     // r(rx,ry,rz) the axis, v(x,y,z) projects on w=a*r with a such that
928     // w.r=a*r.r=v.r
929     double r2=rx*rx+ry*ry+rz*rz;
930     double r=std::sqrt(r2);
931     double a=(rx*x+ry*y+rz*z)/r2;
932     // v=w+V, w remains stable, V=v-w=v-a*r rotates
933     // Rv=w+RV, where RV=cos(theta)*V+sin(theta)*(r cross V)/sqrt(r2)
934     double Vx=x-a*rx,Vy=y-a*ry,Vz=z-a*rz;
935     // cross product of k with V
936     double kVx=ry*Vz-rz*Vy, kVy=rz*Vx-rx*Vz,kVz=rx*Vy-ry*Vx;
937     double c=std::cos(theta),s=std::sin(theta);
938     X=a*rx+c*Vx+s*kVx/r;
939     Y=a*ry+c*Vy+s*kVy/r;
940     Z=a*rz+c*Vz+s*kVz/r;
941   }
942 
943   // type -1 = view point rotation around an axis,
944   // type bit 0 to 7: spot rotation
945   // step is in degree; tstep in seconds
946   // [0,0,0],[rx,ry,rz] axis of the rotation
oxyz_rotate(Graph2d3d * gr,int type,int nstep,double tstep,int danim,double rx,double ry,double rz)947   void oxyz_rotate(Graph2d3d* gr,int type,int nstep,double tstep,int danim,double rx,double ry,double rz){
948     static Fl_Window * w = 0;
949     static Fl_Button * button = 0;
950     if (!w){
951       Fl_Group::current(0);
952       w=new Fl_Window(100,24);
953       button = new Fl_Button(2,2,w->w()-4,w->h()-4);
954       button->label(gettext("Cancel"));
955       w->label(gettext("Rotate Animation"));
956       w->end();
957     }
958     if (Graph3d * gr3 = dynamic_cast<Graph3d *>(gr)){
959       w->set_modal();
960       w->show();
961       w->hotspot(w);
962       Fl::focus(button);
963       double step=2*M_PI/nstep,lx[8],ly[8],lz[8],lX,lY,lZ;
964       quaternion_double qsave(gr3->q);
965       for (int j=0;j<8;++j){
966 	lx[j]=gr3->light_x[j];
967 	ly[j]=gr3->light_y[j];
968 	lz[j]=gr3->light_z[j];
969       }
970       for (int i=1;i<nstep;++i){
971 	double theta=step*i;
972 	// type 0 to 7, rotate light by theta
973 	for (int j=0;j<8;++j){
974 	  if (type & (1<<j)){
975 	    rotate(rx,ry,rz,theta,lx[j],ly[j],lz[j],lX,lY,lZ);
976 	    // cerr << theta << ":" << lX << "," << lY << "," << lZ << '\n';
977 	    gr3->light_x[j]=lX;
978 	    gr3->light_y[j]=lY;
979 	    gr3->light_z[j]=lZ;
980 	  }
981 	}
982 	if (type & (1<<8))
983 	  gr3->q=qsave*rotation_2_quaternion_double(rx,ry,rz,theta*180/M_PI);
984 	gr3->animation_instructions_pos+=danim;
985 	gr3->redraw();
986 	int nwait=int(tstep/0.001),jwait;
987 	if (nwait<=0)
988 	  nwait=1;
989 	for (jwait=0;jwait<nwait;++jwait){
990 	  Fl_Widget *o = Fl::readqueue();
991 	  if (o==button || o==w)
992 	    break;
993 	  else {
994 	    Fl::wait(0.0001);
995 	    usleep(1000);
996 	  }
997 	}
998 	if (jwait<nwait)
999 	  break;
1000       } // end animation for
1001       w->hide();
1002       for (int j=0;j<8;++j){
1003 	gr3->light_x[j]=lx[j];
1004 	gr3->light_y[j]=ly[j];
1005 	gr3->light_z[j]=lz[j];
1006       }
1007       gr3->q=qsave;
1008       gr3->animation_instructions_pos+=danim;
1009       gr3->redraw();
1010     }
1011   }
1012 
cb_Graph2d3d_rotate(Fl_Menu_ * m,void *)1013   static void cb_Graph2d3d_rotate(Fl_Menu_* m , void*) {
1014     if (!Fl::focus())
1015       return;
1016     Graph2d3d * gr = find_graph2d3d(m);
1017     // control window for args of oxyz_rotate
1018     oxyz_rotate(gr,gr->rotanim_type,gr->rotanim_nstep,gr->rotanim_tstep,gr->rotanim_danim,gr->rotanim_rx,gr->rotanim_ry,gr->rotanim_rz);
1019   }
1020 
cb_Graph_Traceclear(Fl_Widget * m,void *)1021   static void cb_Graph_Traceclear(Fl_Widget * m , void*) {
1022     Graph2d3d * gr = find_graph2d3d(m);
1023     if (gr){
1024       gr->trace_instructions.clear();
1025       gr->redraw();
1026     }
1027   }
1028 
do_find_figure(Fl_Widget * widget)1029   Figure * do_find_figure(Fl_Widget * widget){
1030     Fl_Widget * gr = widget;
1031     for (;gr;gr=gr->parent()){
1032       Figure * f =dynamic_cast<Figure *>(gr);
1033       if (f)
1034 	return f;
1035     }
1036     return 0;
1037   }
1038 
find_figure(Fl_Widget * widget)1039   Figure * find_figure(Fl_Widget * widget){
1040     Figure * gr = do_find_figure(widget);
1041     if (gr)
1042       return gr;
1043     gr=do_find_figure(Fl::focus());
1044     //if (!gr)
1045     //  fl_alert("%s","No figure found. Please click in or add one");
1046     return gr;
1047   }
1048 
cb_Graph_Traceobject(Fl_Widget * m,void *)1049   static void cb_Graph_Traceobject(Fl_Widget * m , void*) {
1050     Fl_Widget * wid=Fl::focus();
1051     Figure * f=find_figure(m);
1052     if (f){
1053       const char * ch=fl_input(gettext("Trace which object?"));
1054       if (ch){
1055 	History_Pack * hp=f->geo->hp;
1056 	if (!hp)
1057 	  return;
1058 	int pos;
1059 	if (hp!=get_history_pack(wid,pos))
1060 	  pos=hp->children()-1;
1061 	hp->add_entry(pos);
1062 	string arg="trace("+string(ch)+")";
1063 	hp->set_value(pos,arg,true);
1064       }
1065     }
1066   }
1067 
cb_Graph_Traceon(Fl_Widget * m,void *)1068   static void cb_Graph_Traceon(Fl_Widget * m , void*) {
1069     Graph2d3d * gr = find_graph2d3d(m);
1070     if (gr){
1071       gr->display_mode |= 0x40; // set bit 6
1072       gr->redraw();
1073     }
1074   }
1075 
cb_Graph_Traceoff(Fl_Widget * m,void *)1076   static void cb_Graph_Traceoff(Fl_Widget * m , void*) {
1077     Graph2d3d * gr = find_graph2d3d(m);
1078     if (gr){
1079       gr->display_mode &= (0xffff ^ 0x40);; // clear bit 6
1080       gr->redraw();
1081     }
1082   }
1083 
cb_Graph_Graphon(Fl_Widget * m,void *)1084   static void cb_Graph_Graphon(Fl_Widget * m , void*) {
1085     Graph2d3d * gr = find_graph2d3d(m);
1086     if (gr){
1087       gr->display_mode |= 0x1; // set bit 0
1088       gr->redraw();
1089     }
1090   }
1091 
cb_Graph_Graphoff(Fl_Widget * m,void *)1092   static void cb_Graph_Graphoff(Fl_Widget * m , void*) {
1093     Graph2d3d * gr = find_graph2d3d(m);
1094     if (gr){
1095       gr->display_mode &= (0xffff ^ 0x1); // clear bit 0
1096       gr->redraw();
1097     }
1098   }
1099 
cb_Graph2d3d_Frameoff(Fl_Widget * m,void *)1100   static void cb_Graph2d3d_Frameoff(Fl_Widget * m , void*) {
1101     Graph2d3d * gr = find_graph2d3d(m);
1102     if (gr){
1103       gr->display_mode |= 0x80; // set bit 6
1104       gr->redraw();
1105     }
1106   }
1107 
cb_Graph2d3d_Frameon(Fl_Widget * m,void *)1108   static void cb_Graph2d3d_Frameon(Fl_Widget * m , void*) {
1109     Graph2d3d * gr = find_graph2d3d(m);
1110     if (gr){
1111       gr->display_mode &= (0xffff ^ 0x80);; // clear bit 6
1112       gr->redraw();
1113     }
1114   }
1115 
cb_Graph_Animate(Fl_Widget * m,void *)1116   static void cb_Graph_Animate(Fl_Widget * m , void*) {
1117     Graph2d3d * gr = find_graph2d3d(m);
1118     if (gr){
1119       const char * ch=fl_input(gettext("Frames number? (>0 forward, <0 forward+backward)"),"10");
1120       if (ch){
1121 	int n=atoi(ch);
1122 	gr->animation_instructions=gr->animate(n);
1123 	if (gr->animation_instructions.empty())
1124 	  fl_alert("%s",gettext("Figure must depend on a parameter (Edit->Add parameter)"));
1125 	gr->paused=false;
1126 	gr->animation_dt=0.1;
1127 	gr->display_mode |= 0x2; // set bit 1
1128 	gr->redraw();
1129       }
1130     }
1131   }
1132 
cb_Graph_Unanimate(Fl_Widget * m,void *)1133   static void cb_Graph_Unanimate(Fl_Widget * m , void*) {
1134     Graph2d3d * gr = find_graph2d3d(m);
1135     if (gr){
1136       gr->animation_instructions.clear();
1137       gr->paused=false;
1138       gr->animation_dt=0;
1139       gr->display_mode &= (0xffff ^ 0x2);; // clear bit 1
1140       gr->redraw();
1141     }
1142   }
1143 
1144   Fl_Menu_Item Autoscale_menu[] = {
1145     {gettext("auto"), 0,  0, 0, 64, 0, 0, 14, 56},
1146     {gettext("Autoscale"), 0,  (Fl_Callback*)cb_Graph2d3d_Autoscale, 0, 0, 0, 0, 14, 56},
1147     {gettext("Autoscale (full)"), 0,  (Fl_Callback*)cb_Graph2d3d_AutoscaleFull, 0, 0, 0, 0, 14, 56},
1148     {0},
1149     {0}
1150   };
1151 
1152   Fl_Menu_Item Graph2d3d_menu[] = {
1153     {gettext("M"), 0,  0, 0, 64, 0, 0, 14, 56},
1154     {gettext("View"), 0,  0, 0, 64, 0, 0, 14, 56},
1155     {gettext("Autoscale"), 0,  (Fl_Callback*)cb_Graph2d3d_Autoscale, 0, 0, 0, 0, 14, 56},
1156     {gettext("Autoscale (full)"), 0,  (Fl_Callback*)cb_Graph2d3d_AutoscaleFull, 0, 0, 0, 0, 14, 56},
1157     {gettext("Orthonormalize (2-d)"), 0,  (Fl_Callback*)cb_Graph2d3d_Orthonormalize, 0, 0, 0, 0, 14, 56},
1158     {gettext("Zoom in"), 0,  (Fl_Callback*)cb_Graph2d3d_Zoomin, 0, 0, 0, 0, 14, 56},
1159     {gettext("Zoom out"), 0,  (Fl_Callback*)cb_Graph2d3d_Zoomout, 0, 0, 0, 0, 14, 56},
1160     {gettext("Frame move on"), 0,  (Fl_Callback*)cb_Graph2d3d_Frameon, 0, 0, 0, 0, 14, 56},
1161     {gettext("Frame move off"), 0,  (Fl_Callback*)cb_Graph2d3d_Frameoff, 0, 0, 0, 0, 14, 56},
1162     {gettext("Previous"), 0,  (Fl_Callback*)cb_Graph2d3d_Previous, 0, 0, 0, 0, 14, 56},
1163     {gettext("Next"), 0,  (Fl_Callback*)cb_Graph2d3d_Next, 0, 0, 0, 0, 14, 56},
1164     {gettext("Config"), 0,  (Fl_Callback*)cb_Graph2d3d_Config, 0, 0, 0, 0, 14, 56},
1165     {0},
1166     {gettext("Trace"), 0,  0, 0, 64, 0, 0, 14, 56},
1167     {gettext("Trace clear"), 0,  (Fl_Callback *) cb_Graph_Traceclear, 0, 0, 0, 0, 14, 56},
1168     {gettext("Trace on"), 0,  (Fl_Callback *) cb_Graph_Traceon, 0, 0, 0, 0, 14, 56},
1169     {gettext("Trace off"), 0,  (Fl_Callback *) cb_Graph_Traceoff, 0, 0, 0, 0, 14, 56},
1170     {gettext("Trace object"), 0,  (Fl_Callback *) cb_Graph_Traceobject, 0, 0, 0, 0, 14, 56},
1171     {0},
1172     {gettext("Animation"), 0,  0, 0, 64, 0, 0, 14, 56},
1173     {gettext("Pause"), 0,  (Fl_Callback*)cb_Graph2d3d_Pause, 0, 0, 0, 0, 14, 56},
1174     {gettext("Stop"), 0,  (Fl_Callback*)cb_Graph2d3d_Stop, 0, 0, 0, 0, 14, 56},
1175     {gettext("Restart"), 0,  (Fl_Callback*)cb_Graph2d3d_Restart, 0, 0, 0, 0, 14, 56},
1176     {gettext("Faster (2x)"), 0,  (Fl_Callback*)cb_Graph2d3d_Faster, 0, 0, 0, 0, 14, 56},
1177     {gettext("Slower (2x)"), 0,  (Fl_Callback*)cb_Graph2d3d_Slower, 0, 0, 0, 0, 14, 56},
1178     {gettext("Build animation"), 0,  (Fl_Callback *) cb_Graph_Animate, 0, 0, 0, 0, 14, 56},
1179     {gettext("Unanimate"), 0,  (Fl_Callback *) cb_Graph_Unanimate, 0, 0, 0, 0, 14, 56},
1180     {gettext("Graph on"), 0,  (Fl_Callback *) cb_Graph_Graphon, 0, 0, 0, 0, 14, 56},
1181     {gettext("Graph off"), 0,  (Fl_Callback *) cb_Graph_Graphoff, 0, 0, 0, 0, 14, 56},
1182     {0},
1183     {gettext("3-d"), 0,  0, 0, 64, 0, 0, 14, 56},
1184     {gettext("Mouse plane equation"), 0,  (Fl_Callback*)cb_Graph2d3d_mouse_plan, 0, 0, 0, 0, 14, 56},
1185     {gettext("Oyz view (x=cst=depth)"), 0,  (Fl_Callback*)cb_Graph2d3d_xview, 0, 0, 0, 0, 14, 56},
1186     {gettext("Oxz view (y=cst=depth)"), 0,  (Fl_Callback*)cb_Graph2d3d_yview, 0, 0, 0, 0, 14, 56},
1187     {gettext("Upper view (z=cst=depth)"), 0,  (Fl_Callback*)cb_Graph2d3d_zview, 0, 0, 0, 0, 14, 56},
1188     {gettext("Default view"), 0,  (Fl_Callback*)cb_Graph2d3d_startview, 0, 0, 0, 0, 14, 56},
1189     {gettext("Rotate animation"), 0,  (Fl_Callback*)cb_Graph2d3d_rotate, 0, 0, 0, 0, 14, 56},
1190     {gettext("Hide below depth"), 0,  (Fl_Callback*)cb_Graph2d3d_hide, 0, 0, 0, 0, 14, 56},
1191     {gettext("Show below depth"), 0,  (Fl_Callback*)cb_Graph2d3d_show, 0, 0, 0, 0, 14, 56},
1192     {0}, // end 3-d
1193     {gettext("Export Print"), 0,  0, 0, 64, 0, 0, 14, 56},
1194     {gettext("EPS PNG and preview"), 0,  (Fl_Callback*)cb_Graph2d3d_Preview, 0, 0, 0, 0, 14, 56},
1195     {gettext("3-d to PNG"), 0,  (Fl_Callback*)cb_Graph3dpng, 0, 0, 0, 0, 14, 56},
1196     {gettext("Print"), 0,  (Fl_Callback*)cb_Graph2d3d_Print, 0, 0, 0, 0, 14, 56},
1197     {gettext("Preview (with Latex)"), 0,  (Fl_Callback*)cb_Graph2d3d_LaTeX_Preview, 0, 0, 0, 0, 14, 56},
1198     {gettext("Print (with Latex)"), 0,  (Fl_Callback*)cb_Graph2d3d_LaTeX_Print, 0, 0, 0, 0, 14, 56},
1199     {0},
1200     {0},
1201     {0}
1202   };
1203 
add_mouse_param_group(int x,int y,int w,int h)1204   void Graph2d3d::add_mouse_param_group(int x,int y,int w,int h){
1205     Fl_Group * group = parent();
1206     if (!group) return;
1207     bool is3d=dynamic_cast<Graph3d *>(this);
1208     Fl_Group::current(group);
1209     labelsize(group->labelsize());
1210     //    mouse_param_group=new Fl_Tile(x+w-legende_size,y,legende_size,h);
1211     mouse_param_group=new Fl_Group(x+w-legende_size,y,legende_size,h);
1212     mouse_param_group->box(FL_FLAT_BOX);
1213     mouse_position=new Mouse_Position(x+w-legende_size,y,legende_size,(is3d?3:2)*labelsize(),this);
1214     int bx=x+w-legende_size,by=y+mouse_position->h(),bw=legende_size/3,bh=min(group->labelsize()+3,h/8);
1215     button_group = new Fl_Group(bx,by,legende_size,5*bh);
1216     // Buttons
1217     Fl_Button * bzoomin = new Fl_Button(bx,by,bw,bh,"in");
1218     bzoomin->tooltip(gettext("Zoom in"));
1219     bzoomin->callback(cb_graph_buttons);
1220     Fl_Button * bup = new Fl_Button(bx+bw,by,bw,bh,"@-18");
1221     bup->color(y_axis_color);
1222     bup->tooltip(gettext("Increase y"));
1223     bup->callback(cb_graph_buttons);
1224     Fl_Button * bupright = new Fl_Button(bx+2*bw,by,bw,bh,"@-18");
1225     bupright->color(z_axis_color);
1226     bupright->tooltip(gettext("Increase z (3-d)/Zoom in for y (2-d)"));
1227     bupright->callback(cb_graph_buttons);
1228     by += bh;
1229     Fl_Button * bleft = new Fl_Button(bx,by,bw,bh,"@-1<-");
1230     bleft->when(FL_WHEN_RELEASE);
1231     bleft->color(x_axis_color);
1232     bleft->tooltip(gettext("Decrease x"));
1233     bleft->callback(cb_graph_buttons);
1234     Fl_Button * bortho = new Fl_Button(bx+bw,by,bw,bh,"_|_");
1235     bortho->tooltip(gettext(is3d?"Hide or show below depth":"Orthonormalize"));
1236     bortho->callback(cb_graph_buttons);
1237     Fl_Button * bright = new Fl_Button(bx+2*bw,by,bw,bh,"@-1->");
1238     bright->color(x_axis_color);
1239     bright->tooltip(gettext("Increase x"));
1240     bright->callback(cb_graph_buttons);
1241     by += bh;
1242     Fl_Button * bzoomout = new Fl_Button(bx,by,bw,bh,"out");
1243     bzoomout->tooltip(gettext("Zoom out"));
1244     bzoomout->callback(cb_graph_buttons);
1245     Fl_Button * bdown = new Fl_Button(bx+bw,by,bw,bh,"@-12");
1246     bdown->color(y_axis_color);
1247     bdown->tooltip(gettext("Decrease y"));
1248     bdown->callback(cb_graph_buttons);
1249     Fl_Button * bdownright = new Fl_Button(bx+2*bw,by,bw,bh,"@-12");
1250     bdownright->color(z_axis_color);
1251     bdownright->tooltip(gettext("Decrease z (3-d)/Zoom out in y (2-d)"));
1252     bdownright->callback(cb_graph_buttons);
1253     by += bh;
1254     Fl_Button * bback = new Fl_Button(bx,by,bw,bh,"@-1<-");
1255     bback->tooltip(gettext("Back in cfg history"));
1256     bback->callback(cb_graph_buttons);
1257     Fl_Button * bforw = new Fl_Button(bx+bw,by,bw,bh,"@-1->");
1258     bforw->tooltip(gettext("Forward in cfg history"));
1259     bforw->callback(cb_graph_buttons);
1260     Fl_Button * bcfg = new Fl_Button(bx+2*bw,by,bw,bh,"cfg");
1261     bcfg->tooltip(gettext("Configure screen view and axis"));
1262     bcfg->callback(cb_graph_buttons);
1263     by += bh;
1264     Fl_Button * bpause = new Fl_Button(bx+bw,by,bw,bh,"@>|");
1265     bpause->tooltip(gettext("Stop or restart animation"));
1266     bpause->callback(cb_graph_buttons);
1267     Fl_Menu_Bar * bauto = new Fl_Menu_Bar(bx+2*bw,by,bw,bh,"auto");
1268     bauto->tooltip(gettext("Autoscale"));
1269     int s= Autoscale_menu->size();
1270     Fl_Menu_Item * automenuitem = new Fl_Menu_Item[Autoscale_menu->size()];
1271     for (int i=0;i<s;++i)
1272       *(automenuitem+i)=*(Autoscale_menu+i);
1273     bauto->menu (automenuitem);
1274     menubar= new Fl_Menu_Bar(bx,by,bw,bh,"+");
1275     menubar->tooltip(gettext("Graphic menu"));
1276     s= Graph2d3d_menu->size();
1277     Fl_Menu_Item * menuitem = new Fl_Menu_Item[Graph2d3d_menu->size()];
1278     for (int i=0;i<s;++i)
1279       *(menuitem+i)=*(Graph2d3d_menu+i);
1280     menubar->menu (menuitem);
1281     button_group->end();
1282     int param_group_y=button_group->y()+button_group->h();
1283     param_group = new Fl_Group(x+w-legende_size,param_group_y,legende_size,mouse_param_group->h()-button_group->h()-mouse_position->h());
1284     param_group->box(FL_FLAT_BOX);
1285     param_group->end();
1286     mouse_param_group->end();
1287     group->add(mouse_param_group);
1288     set_colors(group);
1289   }
1290 
Graph2d3d(int x,int y,int w,int h,const char * l,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,double ortho,History_Pack * hp_)1291   Graph2d3d::Graph2d3d(int x,int y,int w,int h,const char * l,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,double ortho,History_Pack * hp_):
1292     Fl_Widget(x,y,w,h,l),
1293     pushed(false),
1294     show_mouse_on_object(false),
1295     mode(255),args_tmp_push_size(0),no_handle(false),
1296     display_mode(0x45),
1297     window_xmin(xmin),window_xmax(xmax),window_ymin(ymin),window_ymax(ymax),window_zmin(zmin),window_zmax(zmax),history_pos(0),
1298     ylegende(2.5),
1299     mouse_param_group(0),mouse_position(0),param_group(0),button_group(0),menubar(0),hp(hp_),
1300 #ifdef IPAQ
1301     npixels(15),
1302 #else
1303     npixels(8),
1304 #endif
1305     show_axes(hp_?giac::show_axes(hp_->contextptr):1),show_names(1),
1306     animation_dt(0),paused(false),animation_instructions_pos(0),
1307     rotanim_type(256),rotanim_danim(0),rotanim_nstep(100),rotanim_tstep(0.03),
1308     rotanim_rx(0),rotanim_ry(0),rotanim_rz(1),
1309     last_event(0),x_tick(1.0),y_tick(1.0),couleur(0),approx(true),hp_pos(-1),moving(false),moving_frame(false),ntheta(24),nphi(18),background_image(0) {
1310     animations.push_back(this);
1311     push_cfg();
1312     struct timezone tz;
1313     gettimeofday(&animation_last,&tz);
1314     legende_size=giac::LEGENDE_SIZE;
1315     x_axis_color=FL_RED;
1316     y_axis_color=dark_green_color;
1317     z_axis_color=FL_BLUE;
1318     current_i=current_j=RAND_MAX;
1319     in_area=false;
1320   }
1321 
Graph2d3d(int x,int y,int w,int h,const char * l,History_Pack * hp_)1322   Graph2d3d::Graph2d3d(int x,int y,int w,int h,const char * l,History_Pack * hp_):
1323     Fl_Widget(x,y,w,h,l),
1324     pushed(false),
1325     show_mouse_on_object(false),
1326     display_mode(0x45),
1327     mode(255),args_tmp_push_size(0),no_handle(false),
1328     window_xmin(Xcas_config.window_xmin),window_xmax(Xcas_config.window_xmax),window_ymin(Xcas_config.window_ymin),window_ymax(Xcas_config.window_ymax),window_zmin(Xcas_config.window_zmin),window_zmax(Xcas_config.window_zmax),history_pos(0),
1329     ylegende(2.5),
1330     mouse_param_group(0),mouse_position(0),param_group(0),button_group(0),menubar(0),hp(hp_),
1331 #ifdef IPAQ
1332     npixels(15),
1333 #else
1334     npixels(8),
1335 #endif
1336     show_axes(hp_?giac::show_axes(hp_->contextptr):1),show_names(1),
1337     animation_dt(0),paused(false),animation_instructions_pos(0),
1338     rotanim_type(256),rotanim_danim(0),rotanim_nstep(100),rotanim_tstep(0.1),
1339     rotanim_rx(0),rotanim_ry(0),rotanim_rz(1),
1340     last_event(0),x_tick(1.0),y_tick(1.0),couleur(0),approx(true),hp_pos(-1),moving(false),moving_frame(false),ntheta(24),nphi(18),background_image(0) {
1341     legende_size=giac::LEGENDE_SIZE;
1342     animations.push_back(this);
1343     struct timezone tz;
1344     gettimeofday(&animation_last,&tz);
1345     push_cfg();
1346     x_axis_color=FL_RED;
1347     y_axis_color=dark_green_color;
1348     z_axis_color=FL_BLUE;
1349   }
1350 
~Graph2d3d()1351   Graph2d3d::~Graph2d3d(){
1352     vector<Graph2d3d *>::iterator it=animations.begin(),itend=animations.end();
1353     for (;it!=itend;++it){
1354       if (*it==this){
1355 	animations.erase(it);
1356 	return;
1357       }
1358     }
1359   }
1360 
Graph2d(int x,int y,int w,int h,const char * l,History_Pack * hp_)1361   Graph2d::Graph2d(int x,int y,int w,int h,const char * l,History_Pack * hp_):
1362     Graph2d3d(x,y,w,h,l,Xcas_config.window_xmin,Xcas_config.window_xmax,Xcas_config.window_ymin,Xcas_config.window_ymax,Xcas_config.window_zmin,Xcas_config.window_zmax,1.0,hp_),
1363     orthonormal_factor(1.0),waiting_click(false)
1364   {
1365     box(FL_FLAT_BOX);
1366     legende_size=max(min(legende_size,w/4),w/6);
1367     resize(x,y,w-legende_size,h);
1368     add_mouse_param_group(x,y,w,h);
1369     waiting_click_value=0;
1370   }
1371 
find_tick(double dx)1372   double find_tick(double dx){
1373     double res=std::pow(10.0,std::floor(std::log10(std::abs(dx))));
1374     int nticks=int(dx/res);
1375     if (nticks<4)
1376       res/=5;
1377     else {
1378       if (nticks<8)
1379 	res/=2;
1380     }
1381     return res;
1382   }
1383 
current_config()1384   std::string Graph2d3d::current_config(){
1385     string res="gl_quaternion=[";
1386     res += print_DOUBLE_(q.x);
1387     res += ",";
1388     res += print_DOUBLE_(q.y);
1389     res += ",";
1390     res += print_DOUBLE_(q.z);
1391     res += ",";
1392     res += print_DOUBLE_(q.w);
1393     res += "]";
1394     return res;
1395   }
1396 
reset_light(unsigned i)1397   void Graph2d3d::reset_light(unsigned i){
1398     light_on[i]=!i;
1399     light_x[i]=0;light_y[i]=0;light_z[i]=1;light_w[i]=0;
1400     float di=i?0:1;
1401     light_diffuse_r[i]=di;light_diffuse_g[i]=di;light_diffuse_b[i]=di;light_diffuse_a[i]=di;
1402     light_specular_r[i]=di;light_specular_g[i]=di;light_specular_b[i]=di;light_specular_a[i]=di;
1403     light_ambient_r[i]=0;light_ambient_g[i]=0;light_ambient_b[i]=0;light_ambient_a[i]=1;
1404     light_spot_x[i]=0;light_spot_y[i]=0;light_spot_z[i]=-1;light_spot_w[i]=0;
1405     light_spot_exponent[i]=0;light_spot_cutoff[i]=180;
1406     light_0[i]=1;light_1[i]=0;light_2[i]=0;
1407   }
1408 
config_light(unsigned i)1409   void Graph2d3d::config_light(unsigned i){
1410     int dx=240,dy=300,l=14;
1411     if (window()){
1412       dx=int(0.7*window()->w());
1413       dy=int(0.5*window()->h());
1414       l=window()->labelsize();
1415     }
1416     static Fl_Window * w = 0;
1417     static Fl_Value_Input * ambient_r=0, * ambient_g=0, *ambient_b=0, *ambient_a=0,
1418       * diffuse_r=0, * diffuse_g=0, *diffuse_b=0, * diffuse_a=0,
1419       * specular_r=0, *specular_g=0, *specular_b=0, * specular_a=0,
1420       * pos_x=0, * pos_y=0, * pos_z=0, * pos_w=0,
1421       * dir_x=0, * dir_y=0, * dir_z=0,
1422       * spot_exponent=0, * spot_cutoff = 0,
1423       * coeff_0 =0, * coeff_1 = 0, * coeff_2 = 0;
1424     static Fl_Check_Button * enabled = 0;
1425     static Fl_Button * button0 = 0 ; // ok
1426     static Fl_Button * button1 =0; // cancel, quit
1427     static Fl_Button * button2 =0; // reset light, stay
1428     static Fl_Button * button3 =0; // cancel changes, stay
1429     static Fl_Button * button4 =0; // apply, stay
1430     if (!w){
1431       Fl_Group::current(0);
1432       w=new Fl_Window(dx,dy);
1433       int dh=dy/7;
1434       int dw=dx/8;
1435       int y_=2;
1436       pos_x=new Fl_Value_Input(dw,y_,dw-2,dh-2,"x");
1437       pos_x->tooltip(gettext("x position of spot"));
1438       pos_y=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"y");
1439       pos_y->tooltip(gettext("y position of spot"));
1440       pos_z=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"z");
1441       pos_z->tooltip(gettext("z position of spot"));
1442       pos_w=new Fl_Value_Input(7*dw,y_,dw-2,dh-2,"w");
1443       pos_w->tooltip(gettext("0 directional light source (e.g. sun), 1 position light (e.g. bulb)"));
1444       y_ += dh;
1445       dir_x=new Fl_Value_Input(dw,y_,dw-2,dh-2,"x->");
1446       dir_x->tooltip(gettext("x direction of spot"));
1447       dir_y=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"y->");
1448       dir_y->tooltip(gettext("y direction of spot"));
1449       dir_z=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"z->");
1450       dir_z->tooltip(gettext("z direction of spot"));
1451       enabled = new Fl_Check_Button(6*dw,y_,2*dw-2,dh-2,"on");
1452       enabled->tooltip(gettext("Turn on/off light"));
1453       // spot_w=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"w");
1454       // spot_w->tooltip(gettext("0 directional or 1 for position"));
1455       y_ += dh;
1456       ambient_r=new Fl_Value_Input(dw,y_,dw-2,dh-2,"amb_r");
1457       ambient_r->tooltip(gettext("ambient red component"));
1458       ambient_g=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"amb_g");
1459       ambient_g->tooltip(gettext("ambient green component"));
1460       ambient_b=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"amb_b");
1461       ambient_b->tooltip(gettext("ambient blue component"));
1462       ambient_a=new Fl_Value_Input(7*dw,y_,dw-2,dh-2,"amb_a");
1463       ambient_a->tooltip(gettext("ambient alpha component"));
1464       y_ += dh;
1465       diffuse_r=new Fl_Value_Input(dw,y_,dw-2,dh-2,"diff_r");
1466       diffuse_r->tooltip(gettext("diffuse red component"));
1467       diffuse_g=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"diff_g");
1468       diffuse_g->tooltip(gettext("diffuse green component"));
1469       diffuse_b=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"diff_b");
1470       diffuse_b->tooltip(gettext("diffuse blue component"));
1471       diffuse_a=new Fl_Value_Input(7*dw,y_,dw-2,dh-2,"diff_a");
1472       diffuse_a->tooltip(gettext("diffuse alpha component"));
1473       y_ += dh;
1474       specular_r=new Fl_Value_Input(dw,y_,dw-2,dh-2,"spec_r");
1475       specular_r->tooltip(gettext("specular red component"));
1476       specular_g=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"spec_g");
1477       specular_g->tooltip(gettext("specular green component"));
1478       specular_b=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"spec_b");
1479       specular_b->tooltip(gettext("specular blue component"));
1480       specular_a=new Fl_Value_Input(7*dw,y_,dw-2,dh-2,"spec_a");
1481       specular_a->tooltip(gettext("specular alpha component"));
1482       y_ += dh;
1483       dw=dx/10;
1484       spot_exponent=new Fl_Value_Input(dw,y_,dw-2,dh-2,"exp");
1485       spot_exponent->tooltip(gettext("Spot attenuation exponent: power of cos(theta), e.g. 1"));
1486       spot_cutoff=new Fl_Value_Input(3*dw,y_,dw-2,dh-2,"cutoff");
1487       spot_cutoff->tooltip(gettext("Spot cutoff angle in 0..90 or 180 for no cutoff"));
1488       coeff_0=new Fl_Value_Input(5*dw,y_,dw-2,dh-2,"att0");
1489       coeff_0->tooltip(gettext("Attenuation constant coefficient"));
1490       coeff_1=new Fl_Value_Input(7*dw,y_,dw-2,dh-2,"att1");
1491       coeff_1->tooltip(gettext("Attenuation linear coefficient"));
1492       coeff_2=new Fl_Value_Input(9*dw,y_,dw-2,dh-2,"att1");
1493       coeff_2->tooltip(gettext("Attenuation quadratic coefficient"));
1494       y_ += dh;
1495       button0 = new Fl_Button(2,y_,dx/5-4,dh-4);
1496       button0->label(gettext("OK"));
1497       button1 = new Fl_Button(dx/5+2,y_,dx/5-4,dh-4);
1498       button1->label(gettext("Cancel"));
1499       button1->shortcut(0xff1b);
1500       button2 = new Fl_Button(2*dx/5+2,y_,dx/5-4,dh-4);
1501       button2->label(gettext("Default"));
1502       button3 = new Fl_Button(3*dx/5+2,y_,dx/5-4,dh-4);
1503       button3->label(gettext("Reset"));
1504       button4 = new Fl_Button(4*dx/5+2,y_,dx/5-4,dh-4);
1505       button4->label(gettext("Apply"));
1506     }
1507     w->label((gettext("Light configuration")+print_INT_(i)).c_str());
1508     change_group_fontsize(w,l);
1509     w->set_modal();
1510     w->show();
1511     autosave_disabled=true;
1512     w->hotspot(w);
1513     Fl::focus(pos_x);
1514     int r=-2;
1515     for (;;) {
1516       if (r==-2){
1517 	diffuse_r->value(light_diffuse_r[i]);
1518 	diffuse_g->value(light_diffuse_g[i]);
1519 	diffuse_b->value(light_diffuse_b[i]);
1520 	diffuse_a->value(light_diffuse_a[i]);
1521 	ambient_r->value(light_ambient_r[i]);
1522 	ambient_g->value(light_ambient_g[i]);
1523 	ambient_b->value(light_ambient_b[i]);
1524 	ambient_a->value(light_ambient_a[i]);
1525 	specular_r->value(light_specular_r[i]);
1526 	specular_g->value(light_specular_g[i]);
1527 	specular_b->value(light_specular_b[i]);
1528 	specular_a->value(light_specular_a[i]);
1529 	pos_x->value(light_x[i]);
1530 	pos_y->value(light_y[i]);
1531 	pos_z->value(light_z[i]);
1532 	pos_w->value(light_w[i]);
1533 	dir_x->value(light_spot_x[i]);
1534 	dir_y->value(light_spot_y[i]);
1535 	dir_z->value(light_spot_z[i]);
1536 	spot_exponent->value(light_spot_exponent[i]);
1537 	spot_cutoff->value(light_spot_cutoff[i]);
1538 	coeff_0->value(light_0[i]);
1539 	coeff_1->value(light_1[i]);
1540 	coeff_2->value(light_2[i]);
1541 	enabled->value(light_on[i]);
1542       }
1543       r=-1;
1544       Fl_Widget *o = Fl::readqueue();
1545       if (!o) Fl::wait();
1546       else {
1547 	if (o == button0) r = 0; // apply and quit
1548 	if (o == button1) r = 1; // cancel changes, quit
1549 	if (o == w) r=1;
1550 	if (o == button2){ // reset light
1551 	  reset_light(i);
1552 	  r=-2;
1553 	}
1554 	if (o == button3) r=-2; // cancel changes, stay heer
1555 	if (o == button4 ) r=2; // apply, stay
1556       }
1557       if (r==0 || r==2 ){
1558 	light_on[i]=enabled->value();
1559 	light_diffuse_r[i]=diffuse_r->value();
1560 	light_diffuse_g[i]=diffuse_g->value();
1561 	light_diffuse_b[i]=diffuse_b->value();
1562 	light_diffuse_a[i]=diffuse_a->value();
1563 	light_ambient_r[i]=ambient_r->value();
1564 	light_ambient_g[i]=ambient_g->value();
1565 	light_ambient_b[i]=ambient_b->value();
1566 	light_ambient_a[i]=ambient_a->value();
1567 	light_specular_r[i]=specular_r->value();
1568 	light_specular_g[i]=specular_g->value();
1569 	light_specular_b[i]=specular_b->value();
1570 	light_specular_a[i]=specular_a->value();
1571 	light_x[i]=pos_x->value();
1572 	light_y[i]=pos_y->value();
1573 	light_z[i]=pos_z->value();
1574 	light_w[i]=pos_w->value();
1575 	light_spot_x[i]=dir_x->value();
1576 	light_spot_y[i]=dir_y->value();
1577 	light_spot_z[i]=dir_z->value();
1578 	light_spot_exponent[i]=spot_exponent->value();
1579 	light_spot_cutoff[i]=spot_cutoff->value();
1580 	light_0[i]=coeff_0->value();
1581 	light_1[i]=coeff_1->value();
1582 	light_2[i]=coeff_2->value();
1583 	redraw();
1584       }
1585       if (r==0 || r==1)
1586 	break;
1587     }
1588     autosave_disabled=false;
1589     w->hide();
1590   }
1591 
1592   // round to 3 decimals
setup_round(double x)1593   double setup_round(double x){
1594     if (x<0)
1595       return -setup_round(-x);
1596     if (x<1e-300)
1597       return 0;
1598     int n=int(floor(log10(x)+.5)); // round to nearest
1599     x=int(floor(x*pow(10.0,3.0-n)+.5));
1600     x=x*pow(10.0,n-3.0);
1601     return x;
1602   }
1603 
config()1604   void Graph2d3d::config(){
1605     int dx=240,dy=300,l=14;
1606     if (window()){
1607       dx=int(0.7*window()->w());
1608       dy=int(0.8*window()->h());
1609       l=window()->labelsize();
1610     }
1611     static Fl_Window * w = 0;
1612     static Fl_Value_Input * wxmin=0, * wxmax=0, *wymin=0, *wymax=0, *wzmin=0, *wzmax=0,*tx=0,*ty=0,*nx=0,*ny=0,*nz=0,*nd=0,*animate=0,*ylegendesize=0,*rx=0,*Theta=0,*Phi=0;
1613     static Fl_Value_Input * rotcfg_type=0,*rotcfg_danim=0,*rotcfg_nstep=0,*rotcfg_rx=0,*rotcfg_ry=0,*rotcfg_rz=0,*rotcfg_tstep=0;
1614     static Fl_Input * autoname_input=0;
1615     static Fl_Button * button0 = 0 ; // ok
1616     static Fl_Button * button1 =0; // cancel
1617     static Fl_Button * button2 =0; // apply
1618     static Fl_Button * button3 =0; // reset
1619     static Fl_Button * button4 =0; // autoscale
1620     static Fl_Button * button5 =0; // round
1621     static Fl_Button * l0=0,*l1=0,*l2=0,*l3=0,*l4=0,*l5=0,*l6=0,*l7=0; // lights
1622     static Fl_Check_Button* c1=0,*c2=0,*c3=0,*ct=0,*landscape=0,*notperspective=0,*lights=0,*shade=0,*blend=0,*fbox=0,*triedre=0,*logx=0,*logy=0;
1623     static Fl_Multiline_Output * currentcfg = 0; // display
1624     if (dy<240)
1625       dy=240;
1626     if (dx<240)
1627       dx=240;
1628     Graph3d * gr3d = dynamic_cast<Graph3d *>(this);
1629     Graph2d * gr2d = dynamic_cast<Graph2d *>(this);
1630     if (!w){
1631       Fl_Group::current(0);
1632       w=new Fl_Window(dx,dy);
1633       int dh=dy/12;
1634       int y_=2;
1635       wxmin=new Fl_Value_Input(dx/6,y_,dx/6-2,dh-4,"WX-");
1636       wxmin->tooltip(gettext("Xmin for visualisation"));
1637       wxmin->labelcolor(x_axis_color);
1638       wxmax=new Fl_Value_Input(dx/2,y_,dx/6-2,dh-4,"WX+");
1639       wxmax->tooltip(gettext("Xmax for visualisation"));
1640       wxmax->labelcolor(x_axis_color);
1641       logx=new Fl_Check_Button(5*dx/6,y_,dx/6-2,dh-4,"X-log");
1642       logx->tooltip(gettext("X Logarithmic scale"));
1643       logx->value(0);
1644       notperspective=new Fl_Check_Button(5*dx/6,y_,dx/6-2,dh-4,"Ortho proj");
1645       notperspective->tooltip(gettext("Orthonormal or perspective"));
1646       notperspective->value(0);
1647       y_ += dh;
1648       wymin=new Fl_Value_Input(dx/6,y_,dx/6-2,dh-4,"WY-");
1649       wymin->tooltip(gettext("Ymin for visualisation"));
1650       wymin->labelcolor(y_axis_color);
1651       wymax=new Fl_Value_Input(dx/2,y_,dx/6-2,dh-4,"WY+");
1652       wymax->tooltip(gettext("Ymax for visualisation"));
1653       wymax->labelcolor(y_axis_color);
1654       logy=new Fl_Check_Button(5*dx/6,y_,dx/6-2,dh-4,"Y-log");
1655       logy->tooltip(gettext("Y Logarithmic scale"));
1656       logy->value(0);
1657       shade=new Fl_Check_Button(5*dx/6,y_,dx/6-2,dh-4,"Gouraud");
1658       shade->tooltip(gettext("Flat or Gouraud shading"));
1659       shade->value(0);
1660       y_ += dh;
1661       wzmin=new Fl_Value_Input(dx/6,y_,dx/6-2,dh-4,"WZ-");
1662       wzmin->tooltip(gettext("Zmin for visualisation"));
1663       wzmin->labelcolor(z_axis_color);
1664       wzmax=new Fl_Value_Input(dx/2,y_,dx/6-2,dh-4,"WZ+");
1665       wzmax->tooltip(gettext("Zmax for visualisation"));
1666       wzmax->labelcolor(z_axis_color);
1667       blend=new Fl_Check_Button(5*dx/6,y_,dx/6-2,dh-4,"Blend");
1668       blend->tooltip(gettext("Enable blending"));
1669       blend->value(1);
1670       y_ += dh;
1671       wxmin->minimum(-1e300);
1672       wxmin->maximum(1e300);
1673       wymin->minimum(-1e300);
1674       wymin->maximum(1e300);
1675       wzmin->minimum(-1e300);
1676       wzmin->maximum(1e300);
1677       fbox=new Fl_Check_Button(2,y_,dx/6-4,dh-4,"Framebox");
1678       fbox->tooltip(gettext("Graphic displayed with a framebox"));
1679       fbox->value(1);
1680       ct=new Fl_Check_Button(dx/6+2,y_,dx/6-4,dh-4,"Pixels");
1681       ct->tooltip(gettext("Ticks in pixels or units"));
1682       ct->value(0);
1683       triedre=new Fl_Check_Button(2*dx/6+2,y_,dx/6-4,dh-4,"Triedre");
1684       triedre->tooltip(gettext("View triedre even if axes are hidden"));
1685       triedre->value(1);
1686       tx=new Fl_Value_Input(2*dx/4+dx/8,y_,dx/4-dx/8,dh-4,"X-tick");
1687       tx->tooltip(gettext("Number of units or pixels for ticks on X"));
1688       ty=new Fl_Value_Input(3*dx/4+dx/8,y_,dx/4-dx/8,dh-4,"Y-tick");
1689       ty->tooltip(gettext("Number of units or pixels for ticks on Y"));
1690       y_ += dh;
1691       nx=new Fl_Value_Input(30,y_,dx/7-30,dh-4,"x*");
1692       nx->tooltip(gettext("x coefficient of mouse plane equation"));
1693       nx->step(0.1);
1694       nx->minimum(-10.1);
1695       nx->maximum(10.1);
1696       ny=new Fl_Value_Input(dx/7+30,y_,dx/7-30,dh-4,"+y*");
1697       ny->tooltip(gettext("y coefficient of mouse plane equation"));
1698       ny->step(0.1);
1699       ny->minimum(-10.1);
1700       ny->maximum(10.1);
1701       nz=new Fl_Value_Input(2*dx/7+30,y_,dx/7-30,dh-4,"+z*");
1702       nz->tooltip(gettext("z coefficient of mouse plane equation"));
1703       nz->step(0.1);
1704       nz->minimum(-10.1);
1705       nz->maximum(10.1);
1706       nd=new Fl_Value_Input(3*dx/7+30,y_,dx/7-30,dh-4,"=");
1707       nd->tooltip(gettext("constant coefficient of mouse plane equation"));
1708       nd->step(0.1);
1709       nd->minimum(-30.1);
1710       nd->maximum(30.1);
1711       rx=new Fl_Value_Input(4*dx/7+30,y_,dx/7-30,dh-4,"r.x");
1712       rx->tooltip(gettext("3d rotation"));
1713       rx->step(1);
1714       rx->minimum(-360);
1715       rx->maximum(360);
1716       Theta=new Fl_Value_Input(5*dx/7+30,y_,dx/7-30,dh-4,"lat");
1717       Theta->tooltip(gettext("Number of latitude divisions for sphere drawing"));
1718       Theta->step(1);
1719       Theta->minimum(5);
1720       Theta->maximum(3000);
1721       Phi=new Fl_Value_Input(6*dx/7+30,y_,dx/7-30,dh-4,"long");
1722       Phi->tooltip(gettext("Number of longitude divisions for sphere drawing"));
1723       Phi->step(1);
1724       Phi->minimum(5);
1725       Phi->maximum(3000);
1726       ylegendesize=new Fl_Value_Input(3*dx/5+30,y_,dx/5-30,dh-4,"y legende size");
1727       ylegendesize->tooltip(gettext("Size in pixels for y graduation printing"));
1728       ylegendesize->step(1);
1729       ylegendesize->minimum(1);
1730       ylegendesize->maximum(200);
1731       y_ += dh;
1732       l0=new Fl_Button(2,y_,dx/10-4,dh-4,"L0");
1733       l0->tooltip(gettext("Configure light"));
1734       l1=new Fl_Button(dx/10+2,y_,dx/10-4,dh-4,"L1");
1735       l1->tooltip(gettext("Configure light"));
1736       l2=new Fl_Button(dx/5+2,y_,dx/10-4,dh-4,"L2");
1737       l2->tooltip(gettext("Configure light"));
1738       l3=new Fl_Button(3*dx/10+2,y_,dx/10-4,dh-4,"L3");
1739       l3->tooltip(gettext("Configure light"));
1740       l4=new Fl_Button(2*dx/5+2,y_,dx/10-4,dh-4,"L4");
1741       l4->tooltip(gettext("Configure light"));
1742       l5=new Fl_Button(dx/2+2,y_,dx/10-4,dh-4,"L5");
1743       l5->tooltip(gettext("Configure light"));
1744       l6=new Fl_Button(3*dx/5+2,y_,dx/10-4,dh-4,"L6");
1745       l6->tooltip(gettext("Configure light"));
1746       l7=new Fl_Button(7*dx/10+2,y_,dx/10-4,dh-4,"L7");
1747       l7->tooltip(gettext("Configure light"));
1748       lights=new Fl_Check_Button(8*dx/10,y_,dx/5-2,dh-4,"Lights");
1749       lights->tooltip(gettext("Show scene with lights"));
1750       lights->value(0);
1751       y_ += dh;
1752       c1=new Fl_Check_Button(0,y_,dx/8,dh-4,gettext("Show names"));
1753       c1->tooltip(gettext("Show/Hide names of geometric objects"));
1754       c1->down_box(FL_DOWN_BOX);
1755       c3=new Fl_Check_Button(2*dx/8,y_,dx/8,dh-4,gettext("Plot names"));
1756       c3->tooltip(gettext("Show/Hide names of parametric and function plots"));
1757       c3->down_box(FL_DOWN_BOX);
1758       landscape=new Fl_Check_Button(dx/2,y_,dx/8,dh-4,gettext("Portrait"));
1759       landscape->tooltip(gettext("Portrait or landscape split"));
1760       landscape->down_box(FL_DOWN_BOX);
1761       autoname_input = new Fl_Input(dx/2+3*dx/8,y_,dx/8,dh-4);
1762       autoname_input->label(gettext("Autoname"));
1763       y_ += dh;
1764       c2=new Fl_Check_Button(0,y_,dx/6,dh-4,gettext("Show axis"));
1765       c2->tooltip(gettext("Show or hide axis"));
1766       c2->down_box(FL_DOWN_BOX);
1767       animate=new Fl_Value_Input(dx/2,y_,dx/6-4,dh-4,"animate");
1768       animate->tooltip(gettext("Time between image changes for animations"));
1769       animate->step(0.1);
1770       animate->minimum(0);
1771       animate->maximum(2);
1772       button5 = new Fl_Button(2*dx/3+2,y_,dx/3-4,dh-4);
1773       button5->label(gettext("Round"));
1774       button5->tooltip(gettext("Round xmin/xmax/ymin/ymax/zmin/zmax"));
1775       y_ += dh;
1776       button3 = new Fl_Button(2,y_,dx/3-4,dh-4);
1777       button3->label(gettext("Default"));
1778       button4 = new Fl_Button(dx/3+2,y_,dx/3-4,dh-4);
1779       button4->label(gettext("Autoscale"));
1780       button2 = new Fl_Button(2*dx/3+2,y_,dx/3-4,dh-4);
1781       button2->label(gettext("Apply"));
1782       button2->shortcut(0xff0d);
1783       y_ += dh;
1784       currentcfg = new Fl_Multiline_Output(dx/6,y_,5*dx/6-4,dh-4);
1785       currentcfg->label(gettext("Cfg"));
1786       currentcfg->tooltip(gettext("Current gl_quaternion= value"));
1787       y_ += dh;
1788       rotcfg_type = new Fl_Value_Input(dx/14+dx/42,y_,dx/14,dh-4);
1789       rotcfg_type->label("Anim");
1790       rotcfg_type->tooltip(gettext("Rotate what: 1 l1, 2 l2, 4 l3, ..., 128 l8, 256 viewpoint"));
1791       rotcfg_tstep=new Fl_Value_Input(8*dx/42,y_,dx/14,dh-4);
1792       rotcfg_tstep->label("t");
1793       rotcfg_tstep->tooltip(gettext("Time for 1 step in s"));
1794       rotcfg_nstep=new Fl_Value_Input(7*dx/21,y_,dx/14,dh-4);
1795       rotcfg_nstep->label("n");
1796       rotcfg_nstep->tooltip(gettext("Number of steps for animation"));
1797       rotcfg_rx=new Fl_Value_Input(10*dx/21,y_,dx/14,dh-4);
1798       rotcfg_rx->label("x");
1799       rotcfg_rx->tooltip(gettext("x rotation axis coordinate"));
1800       rotcfg_ry=new Fl_Value_Input(13*dx/21,y_,dx/14,dh-4);
1801       rotcfg_ry->label("y");
1802       rotcfg_ry->tooltip(gettext("y rotation axis coordinate"));
1803       rotcfg_rz=new Fl_Value_Input(16*dx/21,y_,dx/14,dh-4);
1804       rotcfg_rz->label("z");
1805       rotcfg_rz->tooltip(gettext("z rotation axis coordinate"));
1806       rotcfg_danim=new Fl_Value_Input(19*dx/21,y_,dx/14,dh-4);
1807       rotcfg_danim->label("d");
1808       rotcfg_danim->tooltip(gettext("Other animation change (normally 0)"));
1809       y_ += dh;
1810       button0 = new Fl_Button(2,y_,dx/2-4,dh-4);
1811       button0->label(gettext("OK"));
1812       button1 = new Fl_Button(dx/2+2,y_,dx/2-4,dh-4);
1813       button1->label(gettext("Cancel"));
1814       button1->shortcut(0xff1b);
1815       w->end();
1816       w->resizable(w);
1817     }
1818     w->label(gettext("Graph configuration"));
1819     change_group_fontsize(w,l);
1820     if (window_xmin>window_xmax)
1821       std::swap(window_xmin,window_xmax);
1822     if (window_ymin>window_ymax)
1823       std::swap(window_ymin,window_ymax);
1824     if (window_zmin>window_zmax)
1825       std::swap(window_zmin,window_zmax);
1826     Figure * fig=dynamic_cast<Figure *>(parent());
1827     if (fig){
1828       // landscape->show();
1829       landscape->value(fig->disposition);
1830     }
1831     else
1832       landscape->hide();
1833     window_xmin=setup_round(window_xmin);
1834     window_xmax=setup_round(window_xmax);
1835     window_ymin=setup_round(window_ymin);
1836     window_ymax=setup_round(window_ymax);
1837     window_zmin=setup_round(window_zmin);
1838     window_zmax=setup_round(window_zmax);
1839     double dtmp=(window_xmax-window_xmin)/100;
1840     wxmin->value(window_xmin);
1841     wxmin->step(dtmp);
1842     wxmax->value(window_xmax);
1843     wxmax->step(dtmp);
1844     wxmin->minimum(window_xmin-100000*dtmp);
1845     wxmin->maximum(window_xmax+100000*dtmp);
1846     wxmax->minimum(window_xmin-100000*dtmp);
1847     wxmax->maximum(window_xmax+100000*dtmp);
1848     dtmp=(window_ymax-window_ymin)/100;
1849     wymin->step(dtmp);
1850     wymax->step(dtmp);
1851     wymin->value(window_ymin);
1852     wymax->value(window_ymax);
1853     wymin->minimum(window_ymin-100000*dtmp);
1854     wymin->maximum(window_ymax+100000*dtmp);
1855     wymax->minimum(window_ymin-100000*dtmp);
1856     wymax->maximum(window_ymax+100000*dtmp);
1857     dtmp=(window_zmax-window_zmin)/100;
1858     wzmin->step(dtmp);
1859     wzmax->step(dtmp);
1860     wzmin->value(window_zmin);
1861     wzmax->value(window_zmax);
1862     wzmin->minimum(window_zmin-100000*dtmp);
1863     wzmin->maximum(window_zmax+100000*dtmp);
1864     wzmax->minimum(window_zmin-100000*dtmp);
1865     wzmax->maximum(window_zmax+100000*dtmp);
1866     animate->value(animation_dt);
1867     double a,b,c,i,j,theta,wx=(window_xmax-window_xmin),wy=(window_ymax-window_ymin),wz=(window_zmax-window_zmin);
1868     if (gr3d){
1869       rotcfg_tstep->show(); rotcfg_nstep->show();
1870       rotcfg_rx->show(); rotcfg_ry->show(); rotcfg_rz->show();
1871       rotcfg_danim->show(); rotcfg_type->show();
1872       rotcfg_tstep->value(rotanim_tstep);
1873       rotcfg_nstep->value(rotanim_nstep);
1874       rotcfg_danim->value(rotanim_danim);
1875       rotcfg_type->value(rotanim_type);
1876       rotcfg_rx->value(rotanim_rx);
1877       rotcfg_ry->value(rotanim_ry);
1878       rotcfg_rz->value(rotanim_rz);
1879       notperspective->show();
1880       logx->hide();
1881       logy->hide();
1882       notperspective->value(display_mode & 0x4);
1883       lights->show();
1884       lights->value(display_mode & 0x8);
1885       l0->show();
1886       l1->show();
1887       l2->show();
1888       l3->show();
1889       l4->show();
1890       l5->show();
1891       l6->show();
1892       l7->show();
1893       shade->show();
1894       shade->value( !(display_mode & 0x10) );
1895       blend->show();
1896       blend->value( (display_mode & 0x20) );
1897       gr3d->current_normal(a,b,c);
1898       gr3d->normal2plan(a,b,c); // divides a,b,c by dx^2,...
1899       nx->value(a);
1900       ny->value(b);
1901       nz->value(c);
1902       double x0,y0,z0,t0;
1903       find_xyz(gr3d->x()+gr3d->w()/2,gr3d->y()+gr3d->h()/2,gr3d->depth,x0,y0,z0);
1904       t0=a*x0+b*y0+c*z0;
1905       if (std::abs(t0)<std::abs(window_zmax-window_zmin)/1000)
1906 	t0=0;
1907       nd->value(t0);
1908       // angle
1909       double res1[4],vect[4];
1910       if (std::abs(b)>std::abs(c)){
1911 	res1[0]=b*wx;
1912 	res1[1]=-a*wy;
1913 	res1[2]=0;
1914       }
1915       else {
1916 	res1[0]=c*wx;
1917 	res1[1]=0;
1918 	res1[2]=-a*wz;
1919       }
1920       res1[0] += (window_xmax+window_xmin)/2;
1921       res1[1] += (window_ymax+window_ymin)/2;
1922       res1[2] += (window_zmax+window_zmin)/2;
1923       res1[3]=1;
1924       mult4(gr3d->model,res1,vect);
1925       i=vect[0]/vect[3];
1926       j=vect[1]/vect[3];
1927       // (i,j) are the coordinates of OX0 in (OX,OY)
1928       theta=-std::atan2(j,i)*180/M_PI;
1929       rx->value(theta);
1930       nx->show();
1931       ny->show();
1932       nz->show();
1933       nd->show();
1934       rx->show();
1935       Theta->value(ntheta);
1936       Theta->show();
1937       Phi->value(nphi);
1938       Phi->show();
1939       ylegendesize->hide();
1940     }
1941     else {
1942       rotcfg_tstep->hide(); rotcfg_nstep->hide();
1943       rotcfg_rx->hide(); rotcfg_ry->hide(); rotcfg_rz->hide();
1944       rotcfg_danim->hide(); rotcfg_type->hide();
1945       notperspective->hide();
1946       logx->show();
1947       logy->show();
1948       logx->value(display_mode & (1<<10));
1949       logy->value(display_mode & (1<<11));
1950       lights->hide();
1951       l0->hide();
1952       l1->hide();
1953       l2->hide();
1954       l3->hide();
1955       l4->hide();
1956       l5->hide();
1957       l6->hide();
1958       l7->hide();
1959       shade->hide();
1960       nx->hide();
1961       ny->hide();
1962       nz->hide();
1963       nd->hide();
1964       rx->hide();
1965       Theta->hide();
1966       Phi->hide();
1967       ylegendesize->value(ylegende*labelsize());
1968       ylegendesize->show();
1969     }
1970     double y_scale=(Graph2d3d::h()-((show_axes && gr2d)?((title.empty()?1:2)*labelsize()):0))/(window_ymax-window_ymin);
1971     double x_scale=(Graph2d3d::w()-ylegende*((show_axes && gr2d)?labelsize():0))/(window_xmax-window_xmin);
1972     if (ct->value()){
1973       tx->value(x_tick*x_scale);
1974       ty->value(y_tick*y_scale);
1975     }
1976     else {
1977       tx->value(x_tick);
1978       ty->value(y_tick);
1979     }
1980     fbox->value((display_mode & 0x100));
1981     triedre->value(display_mode & 0x200);
1982     if (!hp)
1983       hp=get_history_pack(this);
1984     if (hp)
1985       autoname_input->value(autoname(hp->contextptr).c_str());
1986     c1->value(show_names & 1);
1987     c3->value(show_names & 2);
1988     c2->value(show_axes);
1989     currentcfg->value(current_config().c_str());
1990     w->set_modal();
1991     w->show();
1992     autosave_disabled=true;
1993     w->hotspot(w);
1994     Fl::focus(wxmin);
1995     int r;
1996     for (;;) {
1997       r=-1;
1998       Fl_Widget *o = Fl::readqueue();
1999       if (!o) Fl::wait();
2000       else {
2001 	if (o == button0) r = 0;
2002 	if (o == button1) r = 1;
2003 	if (o == button2) r = 2;
2004 	if (o==notperspective){
2005 	  display_mode &= (0xffff ^ 0x4);
2006 	  if (notperspective->value())
2007 	    display_mode |= 0x4;
2008 	  redraw();
2009 	}
2010 	if (o==lights){
2011 	  display_mode &= (0xffff ^ 0x8);
2012 	  if (lights->value())
2013 	    display_mode |= 0x8;
2014 	  redraw();
2015 	}
2016 	if (o==shade){
2017 	  display_mode &= (0xffff ^ 0x10);
2018 	  if (!shade->value())
2019 	    display_mode |= 0x10;
2020 	  redraw();
2021 	}
2022 	if (o==blend){
2023 	  display_mode &= (0xffff ^ 0x20);
2024 	  if (blend->value())
2025 	    display_mode |= 0x20;
2026 	  redraw();
2027 	}
2028 	if (o==logx){
2029 	  display_mode &= (0xffff ^ (1<<10));
2030 	  if (logx->value())
2031 	    display_mode |= (1<<10);
2032 	  redraw();
2033 	}
2034 	if (o==logy){
2035 	  display_mode &= (0xffff ^ (1<<11));
2036 	  if (logy->value())
2037 	    display_mode |= (1<<11);
2038 	  redraw();
2039 	}
2040 	if (o==l0){
2041 	  config_light(0);
2042 	}
2043 	if (o==l1){
2044 	  config_light(1);
2045 	  continue;
2046 	}
2047 	if (o==l2){
2048 	  config_light(2);
2049 	  continue;
2050 	}
2051 	if (o==l3){
2052 	  config_light(3);
2053 	  continue;
2054 	}
2055 	if (o==l4){
2056 	  config_light(4);
2057 	  continue;
2058 	}
2059 	if (o==l5){
2060 	  config_light(5);
2061 	  continue;
2062 	}
2063 	if (o==l6){
2064 	  config_light(6);
2065 	  continue;
2066 	}
2067 	if (o==l7){
2068 	  config_light(7);
2069 	  continue;
2070 	}
2071 	if (fig && o == landscape){
2072 	  fig->disposition=landscape->value();
2073 	  fig->resize(fig->x(),fig->y(),fig->w(),fig->h());
2074 	  orthonormalize();
2075 	  fig->redraw();
2076 	}
2077 	if (o==button3 ){
2078 	  wxmin->value(gnuplot_xmin);
2079 	  wxmax->value(gnuplot_xmax);
2080 	  wymin->value(gnuplot_ymin);
2081 	  wymax->value(gnuplot_ymax);
2082 	  wzmin->value(gnuplot_zmin);
2083 	  wzmax->value(gnuplot_zmax);
2084 	  nx->value(0);
2085 	  ny->value(0);
2086 	  nz->value(1);
2087 	  nd->value(0);
2088 	  r=2;
2089 	}
2090 	if (o==ylegendesize){
2091 	  ylegende=ylegendesize->value()/labelsize();
2092 	}
2093 	if (o==button4 ){
2094 	  autoscale(false);
2095 	  wxmin->value(window_xmin);
2096 	  wxmax->value(window_xmax);
2097 	  wymin->value(window_ymin);
2098 	  wymax->value(window_ymax);
2099 	  wzmin->value(window_zmin);
2100 	  wzmax->value(window_zmax);
2101 	}
2102 	if (o==button5){
2103 	  x_tick=find_tick(window_xmax-window_xmin);
2104 	  wxmin->value(int( window_xmin/x_tick -1)*x_tick);
2105 	  wxmax->value(int( window_xmax/x_tick +1)*x_tick);
2106 	  y_tick=find_tick(window_ymax-window_ymin);
2107 	  wymin->value(int( window_ymin/y_tick -1)*y_tick);
2108 	  wymax->value(int( window_ymax/y_tick +1)*y_tick);
2109 	  z_tick=find_tick(window_zmax-window_zmin);
2110 	  wzmin->value(int( window_zmin/z_tick -1)*z_tick);
2111 	  wzmax->value(int( window_zmax/z_tick +1)*z_tick);
2112 	}
2113 	if (o == w) r=1;
2114 	if (r==0 || r==2){
2115 	  rotanim_type=int(rotcfg_type->value());
2116 	  rotanim_danim=int(rotcfg_danim->value());
2117 	  rotanim_tstep=std::abs(rotcfg_tstep->value());
2118 	  rotanim_nstep=max(int(rotcfg_nstep->value()),2);
2119 	  rotanim_rx=rotcfg_rx->value();
2120 	  rotanim_ry=rotcfg_ry->value();
2121 	  rotanim_rz=rotcfg_rz->value();
2122 	  if (rotanim_rx*rotanim_rx+rotanim_ry*rotanim_ry+rotanim_rz*rotanim_rz<1e-6){
2123 	    rotanim_rx=0; rotanim_ry=0; rotanim_rz=1;
2124 	  }
2125 	  animation_dt=std::abs(animate->value());
2126 	  animation_instructions_pos=0;
2127 	  window_xmin=wxmin->value();
2128 	  window_xmax=wxmax->value();
2129 	  window_ymin=wymin->value();
2130 	  window_ymax=wymax->value();
2131 	  window_zmin=wzmin->value();
2132 	  window_zmax=wzmax->value();
2133 	  if (window_xmin>window_xmax)
2134 	    std::swap(window_xmin,window_xmax);
2135 	  if (window_ymin>window_ymax)
2136 	    std::swap(window_ymin,window_ymax);
2137 	  if (window_zmin>window_zmax)
2138 	    std::swap(window_zmin,window_zmax);
2139 	  y_scale=(Graph2d3d::h()-((gr2d && show_axes)?((title.empty()?1:2)*labelsize()):0))/(window_ymax-window_ymin);
2140 	  x_scale=(Graph2d3d::w()-ylegende*((gr2d && show_axes)?labelsize():0))/(window_xmax-window_xmin);
2141 	  if (gr3d){
2142 	    ntheta=int(Theta->value());
2143 	    nphi=int(Phi->value());
2144 	    double a=nx->value(),b=ny->value(),c=nz->value();
2145 	    double aorig=a,borig=b,corig=c;
2146 	    // de-scale a,b,c
2147 	    a *= (window_xmax-window_xmin);
2148 	    b *= (window_ymax-window_ymin);
2149 	    c *= (window_zmax-window_zmin);
2150 	    double n=std::sqrt(a*a+b*b+c*c);
2151 	    if (aorig*aorig+borig*borig+corig*corig<1e-3){
2152 	      q=quaternion_double(1,0,0,0);
2153 	      gr3d->depth=nd->value();
2154 	    }
2155 	    else {
2156 	      a=a/n; b=b/n; c=c/n; // coordinates of OZ
2157 	      // (0,0,depth) -> depth*(a,b,c)
2158 	      // rescale (x,y,z)=depth*(dx*a,dy*b,dz*c)+(tx,ty,tz)
2159 	      // A*x+B*y+C*z=d -> depth=(d-A*tx-B*ty-C*tz)/(A*Zx+B*Zy+C*Zz)
2160 	      n=aorig*(window_xmax-window_xmin)*a+borig*(window_ymax-window_ymin)*b+corig*(window_zmax-window_zmin)*c;
2161 	      gr3d->depth = -2/std::sqrt(double(3.0))*(nd->value()-aorig*(window_xmax+window_xmin)/2-borig*(window_ymax+window_ymin)/2-corig*(window_zmax+window_zmin)/2)/n;
2162 	      // cerr << gr3d->depth << '\n';
2163 	      double A0,B0,C0; // coordinates of OX0
2164 	      if (std::abs(b)>std::abs(c)){
2165 		A0=b;
2166 		B0=-a;
2167 		C0=0;
2168 	      }
2169 	      else {
2170 		A0=c;
2171 		B0=0;
2172 		C0=-a;
2173 	      }
2174 	      n=std::sqrt(A0*A0+B0*B0+C0*C0);
2175 	      A0=A0/n; B0=B0/n; C0=C0/n;
2176 	      double A1,B1,C1; // coordinates of OY0
2177 	      A1=b*C0-c*B0;
2178 	      B1=c*A0-a*C0;
2179 	      C1=a*B0-b*A0;
2180 	      double t=rx->value()*M_PI/180;
2181 	      double A,B,C; // OX coordinates
2182 	      A=cos(t)*A0+sin(t)*A1;
2183 	      B=cos(t)*B0+sin(t)*B1;
2184 	      C=cos(t)*C0+sin(t)*C1;
2185 	      double D,E,F; // OY coordinates
2186 	      D=cos(t)*A1-sin(t)*A0;
2187 	      E=cos(t)*B1-sin(t)*B0;
2188 	      F=cos(t)*C1-sin(t)*C0;
2189 	      // matrix of the rotation in column is [A,B,C] [D,E,F] [a,b,c]
2190 	      /*  1 A D a
2191 		  2 B E b
2192 		  3 C F c
2193 	      */
2194 	      // cerr << "axis " << F-b << "," << a-C << "," << B-D << '\n';
2195 	      double qx,qy,qz,qw;
2196 	      qw=std::sqrt(1+A+E+c)/2;
2197 	      qx=(F-b)/4/qw;
2198 	      qy=(a-C)/4/qw;
2199 	      qz=(B-D)/4/qw;
2200 	      n=std::sqrt(qw*qw+qx*qx+qy*qy+qz*qz);
2201 	      q=quaternion_double(qw/n,-qx/n,-qy/n,-qz/n);
2202 	    }
2203 	  } // end if gr3d
2204 	  show_axes=c2->value();
2205 	  show_names=c1->value() | (c3->value()<< 1);
2206 	  if (ct->value()){
2207 	    x_tick=tx->value()/x_scale;
2208 	    y_tick=ty->value()/y_scale;
2209 	  }
2210 	  else {
2211 	    x_tick=tx->value();
2212 	    y_tick=ty->value();
2213 	  }
2214 	  display_mode &= (0xffff ^ 0x100);
2215 	  if (fbox->value())
2216 	    display_mode |= 0x100;
2217 	  display_mode &= (0xffff ^ 0x200);
2218 	  if (triedre->value())
2219 	    display_mode |= 0x200;
2220 	  if (hp &&strlen(autoname_input->value()))
2221 	    autoname(hp->contextptr)=autoname_input->value();
2222 	  redraw();
2223 	  if (r==0)
2224 	    push_cfg();
2225 	}
2226 	if (r==0 || r==1)
2227 	  break;
2228       } // end else
2229       currentcfg->value(current_config().c_str());
2230     } // end for
2231     autosave_disabled=false;
2232     w->hide();
2233   }
2234 
parameter2slider(const gen & e,const giac::context * contextptr)2235   Gen_Value_Slider * parameter2slider(const gen & e,const giac::context *contextptr){
2236     if (e.is_symb_of_sommet(at_parameter) && e._SYMBptr->feuille.type==_VECT){
2237       vecteur v = *e._SYMBptr->feuille.evalf(1,contextptr).evalf_double(1,contextptr)._VECTptr;
2238       if (v.size()>3 &&v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ && v[3].type == _DOUBLE_ ){
2239 	gen name=e._SYMBptr->feuille._VECTptr->front();
2240 	double step=(v[2]._DOUBLE_val-v[1]._DOUBLE_val)/100.;
2241 	if (v.size()>4 && v[4].type==_DOUBLE_)
2242 	  step=v[4]._DOUBLE_val;
2243 	Fl_Group::current(0);
2244 	Gen_Value_Slider * gvs = new Gen_Value_Slider(0,0,1,1,-2,v[1]._DOUBLE_val,v[2]._DOUBLE_val,step,name.print(contextptr));
2245 	gvs->align(FL_ALIGN_RIGHT);
2246 	gvs->value(v[3]._DOUBLE_val);
2247 	return gvs;
2248       }
2249     }
2250     return 0;
2251   }
2252 
add(const gen & e)2253   void Graph2d3d::add(const gen & e){
2254     context * contextptr=hp?hp->contextptr:get_context(this);
2255     if (e.is_symb_of_sommet(at_trace)){
2256       gen f=symbolic(at_evalf,e._SYMBptr->feuille);
2257       f=protecteval(f,1,contextptr);
2258       trace_instructions.push_back(f);
2259       this->redraw();
2260       return;
2261     }
2262     plot_instructions.push_back(e);
2263     update_infos(e,contextptr);
2264     if (e.is_symb_of_sommet(at_pnt) && e._SYMBptr->feuille.type==_VECT ){
2265       vecteur & v = *e._SYMBptr->feuille._VECTptr;
2266       if (v.size()==3 && v.back().type==_STRNG){
2267 	string newauto=*v.back()._STRNGptr;
2268 	if (newauto.size()>=1 && v[1].type!=_VECT && newauto>=autoname(contextptr)){
2269 	  autoname(contextptr)=newauto;
2270 	  autoname_plus_plus();
2271 	}
2272       }
2273     }
2274     // gen_value_slider inside normal graphic do not work
2275     // especially if you save them, the output by widget_sprint is unusable
2276     Gen_Value_Slider * gvs=0;
2277     if ( (dynamic_cast<Geo2d *>(this) || dynamic_cast<Geo3d *>(this)) && param_group && (gvs=parameter2slider(e,contextptr)) ){
2278       int n=param_group->children();
2279       int x=param_group->x(), y=param_group->y(),h=param_group->h(),w=(6*param_group->w()/7);
2280       int nmax=int(0.5+param_group->h()/(1.5*labelsize()));
2281       if (n>nmax){ // Resize params height h/(n+1)
2282 	for (int i=0;i<n;++i)
2283 	  param_group->child(i)->resize(x,y+h/(n+1)*i,w,h/(n+1));
2284       }
2285       if (n)
2286 	y=param_group->child(n-1)->y()+param_group->child(n-1)->h();
2287       if (n<nmax)
2288 	n=nmax-1;
2289       gvs->resize(x,y,w,param_group->h()/(n+1));
2290       gvs->pos=plot_instructions.size()-1;
2291       param_group->add(gvs);
2292       param_group->redraw();
2293     }
2294     this->redraw();
2295   }
2296 
find_ylegende()2297   void Graph2d3d::find_ylegende(){
2298     const giac::context * contextptr = get_context(this);
2299     vecteur aff=ticks(window_ymin,window_ymax,true);
2300     int affs=aff.size();
2301     fl_font(FL_HELVETICA,labelsize());
2302     int taille=5;
2303     for (int i=0;i<affs;++i){
2304       double d=evalf_double(aff[i],1,contextptr)._DOUBLE_val;
2305       string tmp=print_DOUBLE_(d)+y_axis_unit;
2306       int taillecur=5+int(fl_width(tmp.c_str()));
2307       if (taillecur>taille)
2308 	taille=taillecur;
2309     }
2310     ylegende=double(taille)/labelsize();
2311   }
2312 
autoscale(bool fullview)2313   void Graph2d3d::autoscale(bool fullview){
2314     glequal(false);
2315     if (!plot_instructions.empty()){
2316       // Find the largest and lowest x/y/z in objects (except lines/plans)
2317       vector<double> vx,vy,vz;
2318       int s;
2319       context * contextptr=hp?hp->contextptr:get_context(this);
2320       bool ortho=autoscaleg(plot_instructions,vx,vy,vz,contextptr);
2321       autoscaleminmax(vx,window_xmin,window_xmax,fullview);
2322       if (display_mode & 0x400){
2323 	if (window_xmin<=0){
2324 	  if (vx[0]<=0)
2325 	    window_xmin=-309;
2326 	  else
2327 	    window_xmin=std::log10(vx[0]);
2328 	}
2329 	else
2330 	  window_xmin=std::log10(window_xmin);
2331 	if (window_xmax<=0)
2332 	  window_xmax=-300;
2333 	else
2334 	  window_xmax=std::log10(window_xmax);
2335       }
2336       zoomx(1.0);
2337       autoscaleminmax(vy,window_ymin,window_ymax,fullview);
2338       if (display_mode & 0x800){
2339 	if (window_ymin<=0){
2340 	  if (vy[0]<=0)
2341 	    window_ymin=-309;
2342 	  else
2343 	    window_ymin=std::log10(vy[0]);
2344 	}
2345 	else
2346 	  window_ymin=std::log10(window_ymin);
2347 	if (window_ymax<=0)
2348 	  window_ymax=-300;
2349 	else
2350 	  window_ymax=std::log10(window_ymax);
2351       }
2352       zoomy(1.0);
2353       autoscaleminmax(vz,window_zmin,window_zmax,fullview);
2354       zoomz(1.0);
2355       bool do_ortho=ortho;
2356       if (!do_ortho){
2357 	if (Graph2d * ptr=dynamic_cast<Graph2d *>(this)){
2358 	  double h=this->h()*ptr->orthonormal_factor;
2359 	  double w=this->w();
2360 	  double window_w=window_xmax-window_xmin,window_h=window_ymax-window_ymin;
2361 	  double tst=h/w*window_w/window_h;
2362 	  if (tst>0.7 && tst<1.4)
2363 	    do_ortho=true;
2364 	}
2365       }
2366       if (do_ortho )
2367 	orthonormalize();
2368     }
2369     find_ylegende();
2370     y_tick=find_tick(window_ymax-window_ymin);
2371     redraw();
2372     push_cfg();
2373   }
2374 
glequalv(vecteur & v,bool rmequal)2375   void glequalv(vecteur & v,bool rmequal){
2376     iterateur it=v.begin(),itend=v.end();
2377     if (rmequal){
2378       for (;it!=itend;++it){
2379 	if (it->type==_VECT)
2380 	  glequalv(*it->_VECTptr,rmequal);
2381 	if (it->is_symb_of_sommet(at_equal))
2382 	  *it=symbolic(at_nop,it->_SYMBptr->feuille);
2383       }
2384     }
2385     else {
2386       for (;it!=itend;++it){
2387 	if (it->type==_VECT)
2388 	  glequalv(*it->_VECTptr,rmequal);
2389 	if (it->is_symb_of_sommet(at_nop))
2390 	  *it=symbolic(at_equal,it->_SYMBptr->feuille);
2391       }
2392     }
2393   }
2394 
glequal(bool rmequal)2395   void Graph2d3d::glequal(bool rmequal){
2396     glequalv(plot_instructions,rmequal);
2397   }
2398 
zoomx(double d,bool round)2399   void Graph2d3d::zoomx(double d,bool round){
2400     double x_center=(window_xmin+window_xmax)/2;
2401     double dx=(window_xmax-window_xmin);
2402     if (dx==0)
2403       dx=gnuplot_xmax-gnuplot_xmin;
2404     dx *= d/2;
2405     x_tick = find_tick(dx);
2406     window_xmin = x_center - dx;
2407     if (round)
2408       window_xmin=int( window_xmin/x_tick -1)*x_tick;
2409     window_xmax = x_center + dx;
2410     if (round)
2411       window_xmax=int( window_xmax/x_tick +1)*x_tick;
2412     parent_redraw(this);
2413   }
2414 
zoomy(double d,bool round)2415   void Graph2d3d::zoomy(double d,bool round){
2416     double y_center=(window_ymin+window_ymax)/2;
2417     double dy=(window_ymax-window_ymin);
2418     if (dy==0)
2419       dy=gnuplot_ymax-gnuplot_ymin;
2420     dy *= d/2;
2421     y_tick = find_tick(dy);
2422     window_ymin = y_center - dy;
2423     if (round)
2424       window_ymin=int( window_ymin/y_tick -1)*y_tick;
2425     window_ymax = y_center + dy;
2426     if (round)
2427       window_ymax=int( window_ymax/y_tick +1)*y_tick;
2428     find_ylegende();
2429     parent_redraw(this);
2430   }
2431 
zoomz(double d,bool round)2432   void Graph2d3d::zoomz(double d,bool round){
2433     double z_center=(window_zmin+window_zmax)/2;
2434     double dz=(window_zmax-window_zmin);
2435     if (dz==0)
2436       dz=gnuplot_zmax-gnuplot_zmin;
2437     dz *= d/2;
2438     z_tick=find_tick(dz);
2439     window_zmin = z_center - dz;
2440     if (round)
2441       window_zmin=int(window_zmin/z_tick -1)*z_tick;
2442     window_zmax = z_center + dz;
2443     if (round)
2444       window_zmax=int(window_zmax/z_tick +1)*z_tick;
2445     parent_redraw(this);
2446   }
2447 
2448 
zoom(double d)2449   void Graph2d3d::zoom(double d){
2450     glequal(true);
2451     zoomx(d);
2452     zoomy(d);
2453     zoomz(d);
2454     push_cfg();
2455   }
2456 
2457 
orthonormalize()2458   void Graph2d3d::orthonormalize(){
2459     // don't do anything in base class
2460   }
2461 
latexfilename(const char * filename_)2462   const char * latexfilename(const char * filename_){
2463     if (filename_)
2464       return filename_;
2465     char * filename=file_chooser(gettext("LaTeX filaneme"), "*.tex", "session.tex");
2466     if (!filename)
2467       return 0;
2468     string s=remove_extension(filename)+".tex";
2469     if (is_file_available(s.c_str())){
2470       int i=fl_ask("%s",("File "+s+" exists. Overwrite?").c_str());
2471       if ( !i )
2472 	return 0;
2473     }
2474     return s.c_str();
2475   }
2476 
latex(const char * filename_)2477   const char * Graph2d3d::latex(const char * filename_){
2478     return latexfilename(filename_);
2479   }
2480 
latex(const char * filename_)2481   const char * Graph2d::latex(const char * filename_){
2482     const char * filename=0;
2483     if ( (filename=Graph2d3d::latex(filename_)) ){
2484       double xunit=giac::horiz_latex/(window_xmax-window_xmin);
2485       double yunit=(h()*giac::horiz_latex*orthonormal_factor)/w()/(window_ymax-window_ymin);
2486       graph2tex(filename,plot_instructions,window_xmin,window_xmax,window_ymin,window_ymax,xunit,yunit,false,get_context(this));
2487     }
2488     return filename;
2489   }
2490 
up(double d)2491   void Graph2d3d::up(double d){
2492     glequal(true);
2493     window_ymin += d;
2494     window_ymax += d;
2495     parent_redraw(this);
2496     push_cfg();
2497   }
2498 
down(double d)2499   void Graph2d3d::down(double d){
2500     glequal(true);
2501     window_ymin -= d;
2502     window_ymax -= d;
2503     parent_redraw(this);
2504     push_cfg();
2505   }
2506 
up_z(double d)2507   void Graph2d3d::up_z(double d){
2508     glequal(true);
2509     window_zmin += d;
2510     window_zmax += d;
2511     parent_redraw(this);
2512     push_cfg();
2513   }
2514 
down_z(double d)2515   void Graph2d3d::down_z(double d){
2516     glequal(true);
2517     window_zmin -= d;
2518     window_zmax -= d;
2519     parent_redraw(this);
2520     push_cfg();
2521   }
2522 
left(double d)2523   void Graph2d3d::left(double d){
2524     glequal(true);
2525     window_xmin -= d;
2526     window_xmax -= d;
2527     parent_redraw(this);
2528     push_cfg();
2529   }
2530 
right(double d)2531   void Graph2d3d::right(double d){
2532     glequal(true);
2533     window_xmin += d;
2534     window_xmax += d;
2535     parent_redraw(this);
2536     push_cfg();
2537   }
2538 
set_axes(int b)2539   void Graph2d3d::set_axes(int b){
2540     show_axes = b;
2541     parent_redraw(this);
2542   }
2543 
resize_mouse_param_group(int W)2544   void Graph2d3d::resize_mouse_param_group(int W){
2545     if (mouse_param_group){
2546       change_group_fontsize(mouse_param_group,labelsize());
2547       int x=this->x()+w();
2548       int l=labelsize();
2549       int bh=min(l+3,h()/8);
2550       int y=this->y();
2551       mouse_param_group->resize(x,y,W,h());
2552       bool is3d=dynamic_cast<Graph3d *>(this);
2553       if (mouse_position) mouse_position->resize(x,y,W,(is3d?3:2)*l);
2554       if (mouse_position) y += mouse_position->h();
2555       button_group->resize(x,y,W,5*bh);
2556       y += 5*bh;
2557       param_group->resize(x,y,W,this->y()-y+h());
2558       mouse_param_group->init_sizes();
2559       mouse_param_group->redraw();
2560     }
2561   }
2562 
resize(int X,int Y,int W,int H)2563   void Graph2d3d::resize(int X,int Y,int W,int H){
2564     /*
2565     if (parent() && !dynamic_cast<Figure *>(parent()) && !dynamic_cast<Tableur_Group *>(parent()) && mouse_param_group){
2566       if (parent()->w()!=w()+mouse_param_group->w())
2567 	resize_mouse_param_group(parent()->w()-w());
2568     }
2569     */
2570     Fl_Widget::resize(X,Y,W,H);
2571   }
2572 
copy(const Graph2d3d & gr)2573   void Graph2d3d::copy(const Graph2d3d & gr){
2574     window_xmin=gr.window_xmin;
2575     window_xmax=gr.window_xmax;
2576     window_ymin=gr.window_ymin;
2577     window_ymax=gr.window_ymax;
2578     window_zmin=gr.window_zmin;
2579     window_zmax=gr.window_zmax;
2580     npixels=gr.npixels;
2581     show_axes=gr.show_axes;
2582     show_names=gr.show_names;
2583     history = gr.history;
2584     labelsize(gr.labelsize());
2585     resize_mouse_param_group(gr.mouse_param_group->w());
2586     q=gr.q;
2587     display_mode=gr.display_mode;
2588     // copy lights
2589     for (int i=0;i<8;++i){
2590       light_on[i]=gr.light_on[i];
2591       light_x[i]=gr.light_x[i];
2592       light_y[i]=gr.light_y[i];
2593       light_z[i]=gr.light_z[i];
2594       light_w[i]=gr.light_w[i];;
2595       light_diffuse_r[i]=gr.light_diffuse_r[i];
2596       light_diffuse_g[i]=gr.light_diffuse_g[i];
2597       light_diffuse_b[i]=gr.light_diffuse_b[i];
2598       light_diffuse_a[i]=gr.light_diffuse_a[i];
2599       light_specular_r[i]=gr.light_specular_r[i];
2600       light_specular_g[i]=gr.light_specular_g[i];
2601       light_specular_b[i]=gr.light_specular_b[i];
2602       light_specular_a[i]=gr.light_specular_a[i];
2603       light_ambient_r[i]=gr.light_ambient_r[i];
2604       light_ambient_g[i]=gr.light_ambient_g[i];
2605       light_ambient_b[i]=gr.light_ambient_b[i];
2606       light_ambient_a[i]=gr.light_ambient_a[i];
2607       light_spot_x[i]=gr.light_spot_x[i];
2608       light_spot_y[i]=gr.light_spot_y[i];
2609       light_spot_z[i]=gr.light_spot_z[i];
2610       light_spot_w[i]=gr.light_spot_w[i];
2611       light_spot_exponent[i]=gr.light_spot_exponent[i];
2612       light_spot_cutoff[i]=gr.light_spot_cutoff[i];
2613       light_0[i]=gr.light_0[i];
2614       light_1[i]=gr.light_1[i];
2615       light_2[i]=gr.light_2[i];
2616     }
2617     ntheta=gr.ntheta;
2618     nphi=gr.nphi;
2619   }
2620 
add(const vecteur & v)2621   void Graph2d3d::add(const vecteur & v){
2622     const_iterateur it=v.begin(),itend=v.end();
2623     for (;it!=itend;++it)
2624       add(*it);
2625   }
2626 
do_handle(const gen & g)2627   void Graph2d3d::do_handle(const gen & g){
2628     if (hp){
2629       hp->update_pos=hp_pos;
2630       hp->set_gen_value(hp_pos,g,true);
2631     }
2632   }
2633 
round(double d)2634   int round(double d){
2635     int res=int(floor(d+0.5));
2636     int maxpixels=10000; // maximal number of horizontal or vertical pixels
2637     if (d>maxpixels)
2638       return maxpixels;
2639     if (d<-maxpixels)
2640       return -maxpixels;
2641     return res;
2642   }
2643 
findij(const gen & e0,double x_scale,double y_scale,double & i0,double & j0,GIAC_CONTEXT) const2644   bool Graph2d::findij(const gen & e0,double x_scale,double y_scale,double & i0,double & j0,GIAC_CONTEXT) const {
2645     gen e,f0,f1;
2646     evalfdouble2reim(e0,e,f0,f1,contextptr);
2647     if ((f0.type==_DOUBLE_) && (f1.type==_DOUBLE_)){
2648       if (display_mode & 0x400){
2649 	if (f0._DOUBLE_val<=0)
2650 	  return false;
2651 	f0=std::log10(f0._DOUBLE_val);
2652       }
2653       i0=(f0._DOUBLE_val-window_xmin)*x_scale;
2654       if (display_mode & 0x800){
2655 	if (f1._DOUBLE_val<=0)
2656 	  return false;
2657 	f1=std::log10(f1._DOUBLE_val);
2658       }
2659       j0=(window_ymax-f1._DOUBLE_val)*y_scale;
2660       return true;
2661     }
2662     // cerr << "Invalid drawing data" << '\n';
2663     return false;
2664   }
2665 
chooseinvecteur(const vecteur & v)2666   int chooseinvecteur(const vecteur & v){
2667     int s=v.size();
2668     if (s==0)
2669       setsizeerr();
2670     if ((s==1) || (s>5))
2671       return 0;
2672     fl_font(FL_HELVETICA,10);
2673     fl_message_font(FL_HELVETICA,10);
2674     if (s==2)
2675       return fl_choice("Choose",v[0].print(giac::context0).c_str(),v[1].print(giac::context0).c_str(),NULL);
2676     if (s==3)
2677       return fl_choice("Choose",v[0].print(giac::context0).c_str(),v[1].print(giac::context0).c_str(),v[2].print(giac::context0).c_str());
2678     if (s==4)
2679       return fl_choice("Choose",v[0].print(giac::context0).c_str(),v[1].print(giac::context0).c_str(),v[2].print(giac::context0).c_str(),v[3].print(giac::context0).c_str());
2680     return fl_choice("Choose",v[0].print(giac::context0).c_str(),v[1].print(giac::context0).c_str(),v[2].print(giac::context0).c_str(),v[3].print(giac::context0).c_str(),v[4].print(giac::context0).c_str());
2681   }
2682 
printsemi(GIAC_CONTEXT)2683   string printsemi(GIAC_CONTEXT){
2684     if (xcas_mode(contextptr)==3)
2685       return "�";
2686     else
2687       return ";";
2688   }
2689 
2690 
cas_recalc_name()2691   string cas_recalc_name(){
2692     if (getenv("XCAS_TMP"))
2693       return getenv("XCAS_TMP")+("/#c#"+print_INT_(parent_id));
2694 #ifdef WIN32
2695     return "#c#"+print_INT_(parent_id);
2696 #endif
2697 #ifdef IPAQ
2698     return "/tmp/#c#"+print_INT_(parent_id);
2699 #endif
2700     return home_directory()+"#c#"+print_INT_(parent_id);
2701   }
2702 
orthonormalize()2703   void Graph2d::orthonormalize(){
2704     // Center of the directions, orthonormalize
2705     double h=(this->h()-(show_axes?((title.empty()?1:2)*labelsize()):0))*orthonormal_factor;
2706     double w=this->w()-(show_axes?ylegende*labelsize():0);
2707     double window_w=window_xmax-window_xmin,window_h=window_ymax-window_ymin;
2708     double window_hsize=h/w*window_w;
2709     if (window_h > window_hsize*1.01){ // enlarge horizontally
2710       double window_xcenter=(window_xmin+window_xmax)/2;
2711       double window_wsize=w/h*window_h;
2712       window_xmin=window_xcenter-window_wsize/2;
2713       window_xmax=window_xcenter+window_wsize/2;
2714     }
2715     if (window_h < window_hsize*0.99) { // enlarge vertically
2716       double window_ycenter=(window_ymin+window_ymax)/2;
2717       window_ymin=window_ycenter-window_hsize/2;
2718       window_ymax=window_ycenter+window_hsize/2;
2719     }
2720     x_tick=find_tick(window_xmax-window_xmin);
2721     y_tick=find_tick(window_ymax-window_ymin);
2722     parent_redraw(this);
2723     push_cfg();
2724   }
2725 
mouse_rescale()2726   int Graph2d::mouse_rescale(){
2727     if ( current_i >=0 && current_i <= w() && current_j >= 0 && current_j <= h()){
2728       if (absint(current_i-push_i)>20 && absint(current_j-push_j)>20 ){
2729 	double y_scale=(window_ymax-window_ymin)/(h()-(show_axes?((title.empty()?1:2)*labelsize()):0));
2730 	double x_scale=(window_xmax-window_xmin)/(w()-(show_axes?ylegende*labelsize():0));
2731 	window_xmax=window_xmin+max(current_i,push_i)*x_scale;
2732 	window_xmin=window_xmin+min(current_i,push_i)*x_scale;
2733 	window_ymin=window_ymax-max(current_j,push_j)*y_scale;
2734 	window_ymax=window_ymax-min(current_j,push_j)*y_scale;
2735 	parent_redraw(this);
2736 	push_cfg();
2737       }
2738       else {
2739 	++animation_instructions_pos;
2740 	redraw();
2741       }
2742       return 1;
2743     }
2744     return 0;
2745   }
2746 
2747 
adjust_cursor_point_type()2748   void Graph2d3d::adjust_cursor_point_type(){
2749     context * contextptr=hp?hp->contextptr:get_context(this);
2750     if (abs_calc_mode(contextptr)==38){
2751       double newx,newy,newz;
2752       find_xyz(current_i,current_j,current_depth,newx,newy,newz);
2753       int pos=-1;
2754       gen orig;
2755       gen res=Graph2d3d::geometry_round(newx,newy,newz,find_eps(),orig,pos);
2756       cursor_point_type=pos>=0?6:3;
2757       parent_redraw(this);
2758     }
2759   }
2760 
2761   // common to Graph2d and Geo2d
2762   // MOVE: modify arg_tmp.back()
2763   // PUSH: set pushed to true and mark mouse position
common_in_handle(int event)2764   int Graph2d::common_in_handle(int event){
2765     last_event=event;
2766     if (event== FL_MOUSEWHEEL ){
2767       if (!Fl::event_inside(this))
2768 	return 0;
2769       if (Fl::e_dy<0)
2770 	zoom(0.707);
2771       else
2772 	zoom(1.414);
2773       return 1;
2774     }
2775     int res=handle_mouse(event);
2776     if (event==FL_UNFOCUS){
2777       return 1;
2778     }
2779     int deltax=x(),deltay=y();
2780     context * contextptr=hp?hp->contextptr:get_context(this);
2781     if (event==FL_MOVE || event==FL_DRAG || event==FL_PUSH || event==FL_RELEASE){
2782       current_i=Fl::event_x()-deltax,current_j=Fl::event_y()-deltay; current_depth=0;
2783       if (abs_calc_mode(contextptr)==38)
2784 	adjust_cursor_point_type();
2785     }
2786     int horizontal_pixels=w()-(show_axes?int(ylegende*labelsize()):0);
2787     int vertical_pixels= h()-((show_axes?1:0)+(!title.empty()))*labelsize();
2788     double y_scale=(window_ymax-window_ymin)/vertical_pixels;
2789     double x_scale=(window_xmax-window_xmin)/horizontal_pixels;
2790     if (mode!=255 && abs_calc_mode(contextptr)==38 && event==FL_KEYBOARD){
2791       switch (Fl::event_key()){
2792       case FL_Right:
2793 	if (current_i<horizontal_pixels)
2794 	  ++current_i;
2795 	adjust_cursor_point_type();
2796 	if (mouse_position) mouse_position->redraw();
2797 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2798 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2799 	return 1;
2800       case FL_Left:
2801 	if (current_i>0)
2802 	  --current_i;
2803 	adjust_cursor_point_type();
2804 	if (mouse_position) mouse_position->redraw();
2805 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2806 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2807 	return 1;
2808       case FL_Down:
2809 	if (current_j<vertical_pixels)
2810 	  ++current_j;
2811 	adjust_cursor_point_type();
2812 	if (mouse_position) mouse_position->redraw();
2813 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2814 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2815 	return 1;
2816       case FL_Up:
2817 	if (current_j>0)
2818 	  --current_j;
2819 	adjust_cursor_point_type();
2820 	if (mouse_position) mouse_position->redraw();
2821 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2822 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2823 	return 1;
2824       case FL_Page_Up:
2825 	if (current_j>vertical_pixels/10)
2826 	  current_j -= vertical_pixels/10;
2827 	else
2828 	  current_j =0;
2829 	adjust_cursor_point_type();
2830 	if (mouse_position) mouse_position->redraw();
2831 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2832 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2833 	return 1;
2834       case FL_Page_Down:
2835 	if (current_j<9*vertical_pixels/10)
2836 	  current_j += vertical_pixels/10;
2837 	else
2838 	  current_j=vertical_pixels;
2839 	adjust_cursor_point_type();
2840 	if (mouse_position) mouse_position->redraw();
2841 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2842 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2843 	return 1;
2844       case FL_End:
2845 	if (current_i<9*horizontal_pixels/10)
2846 	  current_i += horizontal_pixels/10;
2847 	else
2848 	  current_i=horizontal_pixels;
2849 	adjust_cursor_point_type();
2850 	if (mouse_position) mouse_position->redraw();
2851 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2852 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2853 	return 1;
2854       case FL_Home:
2855 	if (current_i>horizontal_pixels/10)
2856 	  current_i -= horizontal_pixels/10;
2857 	else
2858 	  current_i=0;
2859 	adjust_cursor_point_type();
2860 	if (mouse_position) mouse_position->redraw();
2861 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2862 	  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2863 	return 1;
2864       case FL_Enter:
2865 	if (Geo2d * geo=dynamic_cast<Geo2d *>(this)){
2866 	  if (!moving){
2867 	    pushed=true;
2868 	    push_i=current_i;
2869 	    push_j=current_j;
2870 	    geo->geo_handle(FL_PUSH);
2871 	    if (moving)
2872 	      return 1;
2873 	  }
2874 	  int res=geo->geo_handle(FL_RELEASE);
2875 	  pushed=false;
2876 	  return res;
2877 	}
2878       } // end switch
2879       if (Graph2d * gr2d= dynamic_cast<Graph2d *>(this)){
2880 	char ch=Fl::event_text()?Fl::event_text()[0]:0;
2881 	if (ch>='a')
2882 	  ch -= 'a'-'A';
2883 	if (ch>='A' && ch<='Z'){
2884 	  gen tmp=gen(string("G")+ch,contextptr);
2885 	  if (tmp.type==_IDNT){
2886 	    tmp=evalf(tmp,1,contextptr);
2887 	    if (tmp.is_symb_of_sommet(at_pnt)){
2888 	      tmp=remove_at_pnt(tmp);
2889 	      if (tmp.is_symb_of_sommet(at_cercle))
2890 		tmp=(tmp._SYMBptr->feuille[0]+tmp._SYMBptr->feuille[1])/2;
2891 	      if (tmp.type==_SYMB)
2892 		tmp=tmp._SYMBptr->feuille;
2893 	      if (tmp.type==_VECT && !tmp._VECTptr->empty())
2894 		tmp=tmp._VECTptr->front();
2895 	      if (tmp.type==_CPLX){
2896 		int horizontal_pixels=w()-(show_axes?int(ylegende*labelsize()):0);
2897 		int vertical_pixels=h()-((show_axes?1:0)+(!title.empty()))*labelsize();
2898 		double y_scale=vertical_pixels/(window_ymax-window_ymin);
2899 		double x_scale=horizontal_pixels/(window_xmax-window_xmin);
2900 		double i,j;
2901 		gr2d->findij(tmp,x_scale,y_scale,i,j,contextptr);
2902 		current_i=int(i+.5);
2903 		current_j=int(j+.5);
2904 		adjust_cursor_point_type();
2905 		if (mouse_position) mouse_position->redraw();
2906 		if (Geo2d * geo=dynamic_cast<Geo2d *>(this))
2907 		  geo->geo_handle(moving?FL_DRAG:FL_MOVE);
2908 		return 1;
2909 	      }
2910 	    }
2911 	  }
2912 	}
2913       }
2914     }
2915     else {
2916       int res=handle_keyboard(event);
2917       if (res)
2918 	return res;
2919     }
2920     bool old_in_area=in_area;
2921     in_area=(current_i>=0 && current_i<=horizontal_pixels && current_j>=0 && current_j<=vertical_pixels);
2922     if (old_in_area!=in_area && !args_tmp.empty())
2923       redraw();
2924     if (event==FL_FOCUS){
2925       if (mouse_position)
2926 	mouse_position->redraw();
2927       return 1;
2928     }
2929     Graph2d * gr2d =dynamic_cast<Graph2d *>(this);
2930     if (gr2d && pushed && mode==255 && Fl::event_button()==FL_RIGHT_MOUSE ){
2931       if (event==FL_DRAG){
2932 	parent_redraw(this);
2933 	return 1;
2934       }
2935       if (event==FL_RELEASE ){
2936 	pushed = false;
2937 	return gr2d->mouse_rescale();
2938       }
2939     }
2940     if (event==FL_RELEASE){
2941       pushed = false;
2942     }
2943     // If the child process expect a user entry, click -> complex number
2944     if ( waiting_click ){
2945       if ( (event==FL_RELEASE) && (current_i < horizontal_pixels) && (current_j < vertical_pixels) ){
2946 	gen a(window_xmin+current_i*x_scale,window_ymax-current_j*y_scale);
2947 	if (waiting_click){
2948 	  waiting_click_value=a;
2949 	  waiting_click=false;
2950 	  return 1;
2951 	}
2952       }
2953       return 1;
2954     }
2955     if (event==FL_PUSH ){
2956       if (this!=Fl::focus()){
2957 	Fl::focus(this);
2958 	in_handle(FL_FOCUS);
2959       }
2960       pushed=true;
2961       push_i=current_i;
2962       push_j=current_j;
2963       push_depth=current_depth;
2964       parent_redraw(this);
2965       return 1;
2966     }
2967     return res;
2968   }
2969 
in_handle(int event)2970   int Graph2d::in_handle(int event){
2971     if (parent() && mouse_param_group->parent()!=parent())
2972       parent()->add(mouse_param_group);
2973     int res=common_in_handle(event);
2974     if (res)
2975       return res;
2976     if (Fl::event_button()==FL_RIGHT_MOUSE){
2977       if (event==FL_DRAG){
2978 	parent_redraw(this);
2979 	return 1;
2980       }
2981       if ( event==FL_RELEASE )
2982 	return mouse_rescale();
2983     }
2984     else {
2985       if (event==FL_DRAG || event==FL_RELEASE){
2986 	double newx,newy,newz;
2987 	int dw=w()-(show_axes?int(ylegende*labelsize()):0),dh=h()-(show_axes?((title.empty()?1:2)*labelsize()):0);
2988 	double dx=window_xmax-window_xmin;
2989 	double dy=window_ymax-window_ymin;
2990 	double x_scale=dx/dw,y_scale=dy/dh;
2991 	newx=(current_i-push_i)*x_scale;
2992 	newy=(push_j-current_j)*y_scale;
2993 	round3(newx,window_xmin,window_xmax);
2994 	round3(newy,window_ymin,window_ymax);
2995 	if (!(display_mode & 0x80)){
2996 	  window_xmin -= newx;
2997 	  window_xmax -= newx;
2998 	  window_ymin -= newy;
2999 	  window_ymax -= newy;
3000 	}
3001 	push_i = current_i;
3002 	push_j = current_j;
3003 	++animation_instructions_pos;
3004 	parent_redraw(this);
3005 	return 1;
3006       }
3007     }
3008     return 0;
3009   }
3010 
geo_find_history_pack(Fl_Widget * wid)3011   History_Pack * geo_find_history_pack(Fl_Widget * wid){
3012     Fl_Group * g = wid->parent();
3013     if (g){
3014       int n=g->children();
3015       for (int i=0;i<n;++i){
3016 	Fl_Widget * w = g->child(i);
3017 	if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(w))
3018 	  if (s->children())
3019 	    w=s->child(0);
3020 	if (History_Pack * h=dynamic_cast<History_Pack *>(w)){
3021 	  return h;
3022 	}
3023       }
3024     }
3025     return 0;
3026   }
3027 
geometry_round_numeric(double x,double y,double eps,bool approx)3028   gen geometry_round_numeric(double x,double y,double eps,bool approx){
3029     return approx?gen(x,y):exact_double(x,eps)+cst_i*exact_double(y,eps);
3030   }
3031 
geometry_round_numeric(double x,double y,double z,double eps,bool approx)3032   gen geometry_round_numeric(double x,double y,double z,double eps,bool approx){
3033     return approx?makevecteur(x,y,z):makevecteur(exact_double(x,eps),exact_double(y,eps),exact_double(z,eps));
3034   }
3035 
round3(double & x,double xmin,double xmax)3036   void round3(double & x,double xmin,double xmax){
3037     double dx=std::abs(xmax-xmin);
3038     double logdx=std::log10(dx);
3039     int ndec=int(logdx)-4;
3040     double xpow=std::pow(10.0,ndec);
3041     int newx=int(x/xpow);
3042     x=newx*xpow;
3043   }
3044 
change_line_type(int & res,bool show_approx,bool & approx,const string & title,bool dim3,bool & formel,bool & untranslate,bool del,int fontsize)3045   int change_line_type(int & res,bool show_approx,bool & approx,const string & title,bool dim3,bool & formel,bool & untranslate,bool del,int fontsize){
3046     static Fl_Window * w = 0;
3047     static Fl_Value_Input * epaisseur=0,*epaisseur_point;
3048     static Fl_Return_Button * button0 = 0 ;
3049     static Fl_Button * button1 =0,*button_color=0,*button2=0;
3050     static Fl_Check_Button * button_approx=0, * button_formel=0,*button_untranslate=0;
3051     static Line_Type *ltres=0;
3052     static Line_Type *lt0=0,*lt1=0,*lt2=0,*lt3=0,*lt4=0,*lt5=0,*lt6=0,*lt7=0;
3053     static Line_Type *pt0=0,*pt1=0,*pt2=0,*pt3=0,*pt4=0,*pt5=0,*pt6=0,*pt7=0;
3054     static Line_Type *st0=0,*st1=0,*st2=0,*st3=0; // quadrant1,2,3,4
3055     static Line_Type *fp0=0,*fp1=0; // fill polygone
3056     static Line_Type *hn0=0,*hn1=0; // hidden_name
3057     if (!w){
3058 #ifdef IPAQ
3059       int dx=240,dy=300;
3060 #else
3061       int dx=25*fontsize, dy=10*fontsize;
3062 #endif
3063       int lignes=6;
3064       Fl_Group::current(0);
3065       w=new Fl_Window(dx,dy);
3066       epaisseur=new Fl_Value_Input(dx/4,2,dx/4-2,dy/lignes-4,gettext("Thickness"));
3067       epaisseur->when(FL_WHEN_CHANGED);
3068       epaisseur->step(0.1);
3069       epaisseur->maximum(8);
3070       epaisseur->minimum(1);
3071       epaisseur_point=new Fl_Value_Input(3*dx/4,2,dx/4-2,dy/lignes-4,gettext("Point width"));
3072       epaisseur_point->when(FL_WHEN_CHANGED);
3073       epaisseur_point->step(0.1);
3074       epaisseur_point->maximum(8);
3075       epaisseur_point->minimum(1);
3076       // ltres->label(gettext("Line type"));
3077       int x=dx/10;
3078       lt0=new Line_Type(x,dy/lignes,dx/10,dy/lignes,0);
3079       x+=lt0->w();
3080       lt1=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_DASH_LINE);
3081       x+=lt1->w();
3082       lt2=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_DOT_LINE);
3083       x+=lt2->w();
3084       lt3=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_DASHDOT_LINE);
3085       x+=lt3->w();
3086       lt4=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_DASHDOTDOT_LINE);
3087       x+=lt4->w();
3088       lt5=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_CAP_FLAT_LINE);
3089       x+=lt5->w();
3090       lt6=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_CAP_ROUND_LINE);
3091       x+=lt6->w();
3092       lt7=new Line_Type(x,dy/lignes,dx/10,dy/lignes,_CAP_SQUARE_LINE);
3093       x+=lt7->w();
3094       x=dx/10;
3095       pt0=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_WIDTH_3);
3096       pt0->show_pnt(true);
3097       pt0->show_line(false);
3098       x+=pt0->w();
3099       pt1=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_LOSANGE | _POINT_WIDTH_3);
3100       pt1->show_pnt(true);
3101       pt1->show_line(false);
3102       x+=pt1->w();
3103       pt2=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_PLUS | _POINT_WIDTH_3);
3104       pt2->show_pnt(true);
3105       pt2->show_line(false);
3106       x+=pt2->w();
3107       pt3=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_CARRE| _POINT_WIDTH_3);
3108       pt3->show_pnt(true);
3109       pt3->show_line(false);
3110       x+=pt3->w();
3111       pt4=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_INVISIBLE | _POINT_WIDTH_3);
3112       pt4->show_pnt(true);
3113       pt4->show_line(false);
3114       x+=pt4->w();
3115       pt5=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_TRIANGLE| _POINT_WIDTH_3);
3116       x+=pt5->w();
3117       pt5->show_pnt(true);
3118       pt5->show_line(false);
3119       pt6=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_ETOILE| _POINT_WIDTH_3);
3120       pt6->show_pnt(true);
3121       pt6->show_line(false);
3122       x+=pt6->w();
3123       pt7=new Line_Type(x,2*dy/lignes,dx/10,dy/lignes,_POINT_POINT |_POINT_WIDTH_3);
3124       pt7->show_pnt(true);
3125       pt7->show_line(false);
3126       x+=pt7->w();
3127       x=dx/20;
3128       st0=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_QUADRANT1);
3129       st0->show_pnt(true);
3130       st0->show_text(true);
3131       st0->show_line(false);
3132       x+=st0->w();
3133       st1=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_QUADRANT2);
3134       st1->show_pnt(true);
3135       st1->show_text(true);
3136       st1->show_line(false);
3137       x+=st1->w();
3138       st2=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_QUADRANT3);
3139       st2->show_pnt(true);
3140       st2->show_text(true);
3141       st2->show_line(false);
3142       x+=st2->w();
3143       st3=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_QUADRANT4);
3144       st3->show_pnt(true);
3145       st3->show_text(true);
3146       st3->show_line(false);
3147       x+=st3->w()+dx/20;
3148       hn0=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,0);
3149       hn0->show_text(true);
3150       hn0->show_line(false);
3151       x+=hn0->w();
3152       hn1=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_HIDDEN_NAME);
3153       hn1->show_text(true);
3154       hn1->show_line(false);
3155       x+=hn1->w()+dx/20;
3156       fp0=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,0);
3157       fp0->show_poly(true);
3158       fp0->show_line(false);
3159       x+=fp0->w();
3160       fp1=new Line_Type(x,3*dy/lignes,dx/10,dy/lignes,_FILL_POLYGON);
3161       fp1->show_poly(true);
3162       fp1->show_line(false);
3163       x+=fp1->w();
3164       ltres = new Line_Type(2,2+4*dy/lignes,dx/5-4,dy/lignes-4,res);
3165       ltres->show_pnt(true);
3166       ltres->show_poly(true);
3167       button_color = new Fl_Button(dx/5+2,2+4*dy/lignes,dx/5-4,dy/lignes-4);
3168       button_formel=new Fl_Check_Button(2*dx/5+2,2+4*dy/lignes,dx/5-4,dy/lignes-4);
3169       button_formel->label("symb");
3170       button_formel->tooltip(gettext("Make point symbolic"));
3171       button_untranslate=new Fl_Check_Button(3*dx/5+2,2+4*dy/lignes,dx/5-4,dy/lignes-4);
3172       button_untranslate->label("untranslate");
3173       button_untranslate->tooltip(gettext("Remove translation"));
3174       button0 = new Fl_Return_Button(2,2+5*dy/lignes,dx/3-4,dy/lignes-4);
3175       button0->shortcut(0xff0d);
3176       button0->label(gettext("OK"));
3177       button1 = new Fl_Button(dx/3+2,2+5*dy/lignes,dx/3-4,dy/lignes-4);
3178       button1->shortcut(0xff1b);
3179       button1->label(gettext("Cancel"));
3180       button2 = new Fl_Button(2*dx/3+2,2+5*dy/lignes,dx/3-4,dy/lignes-4);
3181       button2->label(gettext("Delete"));
3182       button2->tooltip(gettext("Delete current object"));
3183       w->end();
3184       w->resizable(w);
3185       change_group_fontsize(w,fontsize);
3186     }
3187     if (formel){
3188       button_formel->show();
3189       button_formel->value(false);
3190       button_untranslate->show();
3191       button_untranslate->value(false);
3192     }
3193     else {
3194       button_formel->hide();
3195       button_untranslate->hide();
3196     }
3197     if (del)
3198       button2->show();
3199     else
3200       button2->hide();
3201     /*
3202     if (dim3){
3203       pt0->hide(); pt1->hide();
3204       pt2->hide(); pt3->hide();
3205       pt4->hide(); pt5->hide();
3206       pt6->hide(); pt7->hide();
3207     }
3208     else {
3209       pt0->show(); pt1->show();
3210       pt2->show(); pt3->show();
3211       pt4->show(); pt5->show();
3212       pt6->show(); pt7->show();
3213     }
3214     */
3215     static string titlestr;
3216     titlestr=gettext("Object attributs ")+title;
3217     w->label(titlestr.c_str());
3218     int r=-1;
3219     int lt=(res & 0x01c00000);
3220     int pt=(res & 0x0e000000);
3221     int st=(res & 0x30000000);
3222     bool fp=res&0x40000000;
3223     bool hn=res&0x80000000;
3224     int newcol=res;
3225     Fl_Color couleur=Fl_Color(res&0xffff);
3226     epaisseur->value( ((res&0x00070000) >> 16) +1);
3227     epaisseur_point->value( ((res&0x00380000) >> 19) +1);
3228     ltres->show_text(!hn);
3229     ltres->line_type(res);
3230     button_color->color(couleur);
3231     w->set_modal();
3232     w->show();
3233     autosave_disabled=true;
3234     w->hotspot(w);
3235     Fl::focus(epaisseur);
3236     for (;;) {
3237       Fl_Widget *o = Fl::readqueue();
3238       if (!o) Fl::wait();
3239       else {
3240 	if (o == button0) {r = 0; break;}
3241 	if (o == button1) {r = 1; break;}
3242 	if (o == button2) {r = 2; break;}
3243 	if (o==lt0 || o==lt1 || o==lt2 || o==lt3 || o==lt4 || o==lt5 || o==lt6 || o==lt7) {
3244 	  lt=(w->find(o)-w->find(lt0)) << 22;
3245 	}
3246 	if (o==pt0 || o==pt1 || o==pt2 || o==pt3 || o==pt4 || o==pt5 || o==pt6 || o==pt7) {
3247 	  pt=(w->find(o)-w->find(pt0)) << 25;
3248 	}
3249 	if (o==st0 || o==st1 || o==st2 || o==st3){
3250 	  st=(w->find(o)-w->find(st0)) << 28;
3251 	}
3252 	if (o==button_color){
3253 	  couleur=fl_show_colormap(couleur);
3254 	  button_color->color(couleur);
3255 	}
3256 	// if (o==button_approx)
3257 	//  button_approx->value(!button_approx->value());
3258 	if (o==fp0)
3259 	  fp=false;
3260 	if (o==fp1)
3261 	  fp=true;
3262 	if (o==hn0)
3263 	  hn=false;
3264 	if (o==hn1)
3265 	  hn=true;
3266 	newcol = couleur;
3267 	newcol += Min(8,Max(0,int(epaisseur->value())-1))*_LINE_WIDTH_2;
3268 	newcol += Min(8,Max(0,int(epaisseur_point->value())-1))*_POINT_WIDTH_2;
3269 	newcol += lt+pt+st;
3270 	if (fp)
3271 	  newcol += _FILL_POLYGON;
3272 	if (hn)
3273 	  newcol += _HIDDEN_NAME;
3274 	ltres->line_type(newcol);
3275 	if (o == w) { r=1; break; }
3276       }
3277     }
3278     autosave_disabled=false;
3279     w->hide();
3280     if (!r){
3281       res=newcol;
3282       if (formel){
3283 	formel=button_formel->value();
3284 	untranslate=button_untranslate->value();
3285       }
3286     }
3287     return r;
3288   }
3289 
3290   bool is_numeric(const gen & a);
is_numeric(const vecteur & v)3291   bool is_numeric(const vecteur & v){
3292     const_iterateur it=v.begin(),itend=v.end();
3293     for (;it!=itend;++it){
3294       if (!is_numeric(*it))
3295 	return false;
3296     }
3297     return true;
3298   }
3299 
is_numeric(const gen & a)3300   bool is_numeric(const gen & a){
3301     switch (a.type){
3302     case _DOUBLE_: case _INT_: case _ZINT: case _REAL:
3303       return true;
3304     case _CPLX:
3305       return is_numeric(*a._CPLXptr) && is_numeric(*(a._CPLXptr+1));
3306     case _VECT:
3307       return is_numeric(*a._VECTptr);
3308     case _FRAC:
3309       return is_numeric(a._FRACptr->num) && is_numeric(a._FRACptr->den);
3310     case _SYMB:
3311       if (a.is_symb_of_sommet(at_prod) || a.is_symb_of_sommet(at_inv) || a.is_symb_of_sommet(at_neg) || a.is_symb_of_sommet(at_plus))
3312 	return is_numeric(a._SYMBptr->feuille);
3313     default:
3314       return false;
3315     }
3316   }
3317 
change_attributs(int hp_pos)3318   void Graph2d3d::change_attributs(int hp_pos){
3319     if (!hp || hp_pos<0)
3320       return;
3321     gen g=hp->parse(hp_pos);
3322     const giac::context * contextptr = hp->contextptr;
3323     gen g2(g),pntname,delta,description;
3324     if (g.is_symb_of_sommet(at_sto)){
3325       gen & gf=g._SYMBptr->feuille;
3326       if (gf.type==_VECT && gf._VECTptr->size()==2){
3327 	g2=gf._VECTptr->front();
3328 	pntname=gf._VECTptr->back();
3329 	description=gf._VECTptr->front();
3330       }
3331     }
3332     bool changepntname=is_zero(pntname.type);
3333     if (changepntname){
3334       pntname=gen(autoname(hp->contextptr),hp->contextptr);
3335       description=g;
3336       autoname_plus_plus();
3337     }
3338     // A:=point() or A:=point()+...
3339     if (g2.is_symb_of_sommet(at_plus)){
3340       gen & g2f=g2._SYMBptr->feuille;
3341       if (g2f.type==_VECT && g2f._VECTptr->size()>=2){
3342 	g2=g2f._VECTptr->front();
3343 	delta=symbolic(at_plus,vecteur(g2f._VECTptr->begin()+1,g2f._VECTptr->end()));
3344       }
3345     }
3346     int def=default_color(hp->contextptr);
3347     if (g2.is_symb_of_sommet(at_couleur) || g2.is_symb_of_sommet(at_display)){
3348       g2=g2._SYMBptr->feuille;
3349       if (g2.type==_VECT && g2._VECTptr->size()==2 && g2._VECTptr->back().type==_INT_){
3350 	def=g2._VECTptr->back().val;
3351 	g2=g2._VECTptr->front();
3352       }
3353     }
3354     if (g2.type==_SYMB){
3355       gen g3=g2._SYMBptr->feuille;
3356       if (g3.type!=_VECT)
3357 	g3=gen(vecteur(1,g3),_SEQ__VECT);
3358       if (g3.type==_VECT && !g3._VECTptr->empty()){
3359 	vecteur attributs(1,def);
3360 	int s=read_attributs(*g3._VECTptr,attributs,contextptr);
3361 	vecteur v3(g3._VECTptr->begin(),g3._VECTptr->begin()+s);
3362 	if (s){
3363 	  int g6=attributs[0].val;
3364 	  bool b,formel=g2.is_symb_of_sommet(at_point) && is_numeric(v3),untranslate=false;
3365 	  int r=change_line_type(g6,false,b,pntname.print(contextptr)+": "+description.print(contextptr),(dynamic_cast<Graph3d *>(this)),formel,untranslate,true,labelsize());
3366 	  if (r!=1){
3367 	    if (untranslate)
3368 	      delta=0;
3369 	    if (r==2){
3370 	      hp->remove_entry(hp_pos);
3371 	      hp->update();
3372 	      hp->resize();
3373 	    }
3374 	    else {
3375 	      if (changepntname || formel || untranslate || g6!=attributs[0].val){
3376 		int v3s=0;
3377 		vecteur savev;
3378 		if (formel){
3379 		  v3s=v3.size();
3380 		  if (v3s>3)
3381 		    v3s=3;
3382 		  if (v3s==1){
3383 		    v3.push_back(im(v3[0],contextptr));
3384 		    v3[0]=re(v3[0],contextptr);
3385 		    v3s=2;
3386 		  }
3387 		  if (v3s>0){
3388 		    savev.push_back(makevecteur(v3[0],window_xmin,window_xmax));
3389 		    v3[0]=gen(pntname.print(contextptr)+"x",hp->contextptr);
3390 		  }
3391 		  if (v3s>1){
3392 		    savev.push_back(makevecteur(v3[1],window_ymin,window_ymax));
3393 		    v3[1]=gen(pntname.print(contextptr)+"y",hp->contextptr);
3394 		  }
3395 		  if (v3s>2){
3396 		    savev.push_back(makevecteur(v3[2],window_zmin,window_zmax));
3397 		    v3[2]=gen(pntname.print(contextptr)+"z",hp->contextptr);
3398 		  }
3399 		}
3400 		gen g7(symbolic(g2._SYMBptr->sommet,gen(v3,_SEQ__VECT)));
3401 		g7=add_attributs(g7,g6,contextptr);
3402 		g7=symbolic(at_sto,makevecteur((is_zero(delta)?g7:symbolic(at_plus,makevecteur(g7,delta))),pntname));
3403 		hp->set_gen_value(hp_pos,g7,false);
3404 		for (int k=v3s-1;k>=0;k--){
3405 		  hp->add_entry(hp_pos);
3406 		  hp->set_gen_value(hp_pos,symbolic(at_assume,symbolic(at_equal,makevecteur(v3[k],savev[k]))),false);
3407 		}
3408 		hp->update(hp_pos-1);
3409 	      }
3410 	    } // end else r==-1
3411 	  } // end if (r)
3412 	} // end if (s)
3413       }
3414     }
3415     hp->focus(hp_pos);
3416   }
3417 
change_attributs()3418   void Graph2d3d::change_attributs(){
3419     if (!hp)
3420       return;
3421     if (!selected.empty()){
3422       int i=findfirstpoint(selection2vecteur(selected));
3423       if (i>=0 && i<selected.size())
3424 	hp_pos=selected[i];
3425       else
3426 	hp_pos=selected.front();
3427       change_attributs(hp_pos);
3428       selected.clear();
3429     } // end if selected.empty()
3430   }
3431 
find_eps()3432   double Graph2d3d::find_eps(){
3433     double dx=window_xmax-window_xmin;
3434     double dy=window_ymax-window_ymin;
3435     double dz=window_zmax-window_zmin;
3436     double eps,epsx,epsy;
3437     int L=h()>w()?w():h();
3438     Graph3d * gr3d=dynamic_cast<Graph3d *>(this);
3439     epsx=(npixels*dx)/(gr3d?L:w());
3440     epsy=(npixels*dy)/(gr3d?L:h());
3441     eps=(epsx<epsy)?epsy:epsx;
3442     if (gr3d && dz>dy && dz >dx){
3443       eps=npixels*dz/L;
3444       eps *= 2;
3445     }
3446     return eps;
3447   }
3448 
geo_handle(int event)3449   int Graph2d3d::geo_handle(int event){
3450     Graph3d * gr3d = dynamic_cast<Graph3d *>(this);
3451     Graph2d * gr2d = dynamic_cast<Graph2d *>(this);
3452     if (!gr2d && !gr3d)
3453       return 0;
3454     if (!hp)
3455       return 0;
3456     if (gr3d && !gr3d->push_in_area){
3457       if (event==FL_RELEASE && Fl::event_button()== FL_RIGHT_MOUSE ){
3458 	pushed=moving=moving_frame=false;
3459 	change_attributs();
3460 	args_tmp.clear();
3461 	return 1;
3462       }
3463       return 0;
3464     }
3465     if ( (event==FL_KEYBOARD && Fl::event_key()==FL_Escape ) || (!in_area && event==FL_RELEASE) ){
3466       pushed=false;
3467       moving=moving_frame=false;
3468       args_tmp.clear();
3469       redraw();
3470       return 1;
3471     }
3472     context * contextptr=hp?hp->contextptr:get_context(this);
3473     double eps=find_eps();
3474     int pos;
3475     gen tmp,tmp2,decal;
3476     if ( pushed && !moving && !moving_frame && mode ==0 && in_area && event==FL_DRAG){
3477       redraw();
3478       return 1;
3479     }
3480     if (mode>=2 && event==FL_MOVE && args_tmp.size()>mode)
3481       event=FL_RELEASE;
3482     if ( in_area && ((mode!=1 && event==FL_DRAG) || event==FL_PUSH || event==FL_RELEASE || (mode>=2 && event==FL_MOVE)) ){
3483       double newx,newy,newz;
3484       find_xyz(current_i,current_j,current_depth,newx,newy,newz);
3485       round3(newx,window_xmin,window_xmax);
3486       round3(newy,window_ymin,window_ymax);
3487       if (gr3d)
3488 	round3(newz,window_zmin,window_zmax);
3489       tmp=geometry_round(newx,newy,newz,eps,tmp2,pos,mode==0 || (args_tmp.size()==mode && function_final.type==_FUNC && equalposcomp(transformation_functions,*function_final._FUNCptr)),event==FL_RELEASE);
3490       if (tmp.type==_VECT && tmp._VECTptr->size()==3){
3491 	tmp.subtype=_SEQ__VECT;
3492 	tmp=symbolic(at_point,tmp);
3493       }
3494       else {
3495 	if (tmp.type!=_IDNT && !tmp.is_symb_of_sommet(at_extract_measure)){
3496 	  tmp=symbolic(at_point,makevecteur(re(tmp,contextptr),im(tmp,contextptr)));
3497 	}
3498       }
3499     }
3500     double newx,newy,newz;
3501     if (gr2d){
3502       int dw=w()-(show_axes?int(ylegende*labelsize()):0),dh=h()-(show_axes?((title.empty()?1:2)*labelsize()):0);
3503       double dx=window_xmax-window_xmin;
3504       double dy=window_ymax-window_ymin;
3505       double x_scale=dx/dw,y_scale=dy/dh;
3506       newx=(current_i-push_i)*x_scale;
3507       newy=(push_j-current_j)*y_scale;
3508       newz=0;
3509     }
3510     else {
3511       double x1,y1,z1,x2,y2,z2;
3512       find_xyz(current_i,current_j,current_depth,x1,y1,z1);
3513       find_xyz(push_i,push_j,push_depth,x2,y2,z2);
3514       newx=x1-x2; newy=y1-y2; newz=z1-z2;
3515     }
3516     round3(newx,window_xmin,window_xmax);
3517     round3(newy,window_ymin,window_ymax);
3518     if (gr3d){
3519       round3(newz,window_zmin,window_zmax);
3520       decal=in_area?geometry_round_numeric(newx,newy,newz,eps,approx):0;
3521     }
3522     else
3523       decal=in_area?geometry_round_numeric(newx,newy,eps,approx):0;
3524     // cerr << in_area << " " << decal << '\n';
3525     if (event==FL_RELEASE && Fl::event_button()== FL_RIGHT_MOUSE && (is_zero(decal)) ){
3526       pushed=moving=moving_frame=false;
3527       change_attributs();
3528       args_tmp.clear();
3529       return 1;
3530     }
3531     if (mode==0 || mode==255) {
3532       if (event==FL_PUSH){
3533 	// select object && flag to move it
3534 	if (mode==0 && pos>=0){
3535 	  if (tmp.type==_IDNT){
3536 	    drag_original_value=tmp2;
3537 	    drag_name=tmp;
3538 	  }
3539 	  else {
3540 	    drag_original_value=hp->parse(pos);
3541 	    drag_name=0;
3542 	  }
3543 	  hp_pos=pos;
3544 	  moving = true;
3545 	}
3546 	else { // nothing selected, move frame
3547 	  if (!(display_mode & 0x80)) // disabled by default in 3-d
3548 	    moving_frame=true;
3549 	}
3550 	return 1;
3551       }
3552       if (moving_frame && (event==FL_DRAG || event==FL_RELEASE) ){
3553 	window_xmin -= newx;
3554 	window_xmax -= newx;
3555 	window_ymin -= newy;
3556 	window_ymax -= newy;
3557 	window_zmin -= newz;
3558 	window_zmax -= newz;
3559 	push_i = current_i;
3560 	push_j = current_j;
3561 	redraw();
3562 	if (event==FL_RELEASE)
3563 	  moving_frame=false;
3564 	return 1;
3565       }
3566       if (mode==255)
3567 	return 0;
3568       if (moving && (event==FL_DRAG || event==FL_RELEASE) ){
3569 	if (mouse_position) mouse_position->redraw();
3570 	// cerr << current_i << " " << current_j << '\n';
3571 	// avoid point()+complex+complex+complex
3572 	gen newval;
3573 	if (drag_original_value.is_symb_of_sommet(at_plus) && drag_original_value._SYMBptr->feuille.type==_VECT && drag_original_value._SYMBptr->feuille._VECTptr->size()>=2){
3574 	  vecteur v=*drag_original_value._SYMBptr->feuille._VECTptr;
3575 	  if (v[1].is_symb_of_sommet(at_nop))
3576 	    v[1]=v[1]._SYMBptr->feuille;
3577 	  newval=symbolic(at_plus,makevecteur(v[0],symbolic(at_nop,ratnormal(_plus(vecteur(v.begin()+1,v.end()),contextptr)+decal))));
3578 	}
3579 	else {
3580 	  newval=is_zero(decal)?drag_original_value:symbolic(at_plus,makevecteur(drag_original_value,symbolic(at_nop,decal)));
3581 	}
3582 	int dclick = Fl::event_clicks() || drag_original_value.type==_VECT;
3583 	if (!dclick){
3584 	  if (drag_name.type==_IDNT)
3585 	    do_handle(symbolic(at_sto,makevecteur(in_area?newval:drag_original_value,drag_name)));
3586 	  else
3587 	    do_handle(in_area?newval:drag_original_value);
3588 	}
3589 	if (event==FL_RELEASE)
3590 	  moving=false;
3591 	if (event==FL_RELEASE && dclick ){
3592 	  if(is_zero(decal))
3593 	    change_attributs(); // Change object properties
3594 	}
3595 	selected.clear();
3596 	redraw();
3597 	return 1;
3598       }
3599       return 0;
3600     }
3601     selected.clear();
3602     if (mode==1){
3603       if (function_final!=at_point){
3604 	if (event==FL_RELEASE){
3605 	  string args=autoname(contextptr)+":=";
3606 	  if (function_final.type==_FUNC)
3607 	    args += function_final._FUNCptr->ptr()->s;
3608 	  args +="(";
3609 	  if (function_final==at_plotode)
3610 	    args += fcnfield + "," + fcnvars + "," +tmp.print(contextptr) + ",plan)";
3611 	  else
3612 	    args += tmp.print(contextptr) + ")";
3613 	  autoname_plus_plus();
3614 	  hp->set_value(-1,args,true);
3615 	}
3616 	if (event==FL_PUSH || event==FL_DRAG || event==FL_RELEASE)
3617 	  return 1;
3618 	return 0;
3619       }
3620       // point|segment mode
3621       if (event==FL_RELEASE){
3622 	hp_pos=-1;
3623 	if (hp && !args_tmp.empty() && (std::abs(push_i-current_i)>npixels || std::abs(push_j-current_j)>npixels || (gr3d && std::abs(push_depth-current_depth) >0)) ){
3624 	  // make a segment
3625 	  gen val1,val2;
3626 	  if (in_area && args_tmp.front().is_symb_of_sommet(at_point)){
3627 	    val1=gen(autoname(hp->contextptr),hp->contextptr);
3628 	    // put in last history pack level
3629 	    hp->set_gen_value(-1,symbolic(at_sto,makevecteur(add_attributs(args_tmp.front(),couleur,contextptr),val1)),false);
3630 	    hp_pos=hp->children()-1;
3631 	    autoname_plus_plus();
3632 	  }
3633 	  else
3634 	    val1=args_tmp.front();
3635 	  if (in_area && tmp.is_symb_of_sommet(at_point)){
3636 	    val2=gen(autoname(hp->contextptr),hp->contextptr);
3637 	    gen tmp3=symbolic(at_sto,makevecteur(add_attributs(tmp,couleur,contextptr),val2));
3638 	    hp->set_gen_value(-1,tmp3,false);
3639 	    if (hp_pos<0) hp_pos=hp->children()-1;
3640 	    autoname_plus_plus();
3641 	  }
3642 	  else
3643 	    val2=tmp;
3644 	  if (in_area){
3645 	    gen tmp3=add_attributs(symbolic(at_segment,makevecteur(val1,val2)),couleur,contextptr);
3646 	    string v1v2=val1.print(contextptr)+val2.print(contextptr);
3647 	    gen g1g2(v1v2,hp->contextptr);
3648 	    if (g1g2.type!=_IDNT)
3649 	      g1g2=gen(v1v2+"_",hp->contextptr);
3650 	    tmp3=symbolic(at_sto,makevecteur(tmp3,g1g2));
3651 	    hp->set_gen_value(-1,tmp3,false);
3652 	    if (hp_pos<0) hp_pos=hp->children()-1;
3653 	    hp->update(hp_pos);
3654 	  }
3655 	  return 1;
3656 	}
3657 	if (in_area && tmp.type!=_IDNT)
3658 	  do_handle(symbolic(at_sto,makevecteur(add_attributs(tmp,couleur,contextptr),gen(autoname(hp->contextptr),hp->contextptr))));
3659 	// element
3660 	if (tmp.type==_IDNT && tmp2.type==_SYMB && !equalposcomp(point_sommet_tab_op,tmp2._SYMBptr->sommet)){
3661 	  // tmp2 is the geo object, find parameter value
3662 	  double newx,newy,newz;
3663 	  find_xyz(current_i,current_j,current_depth,newx,newy,newz);
3664 	  round3(newx,window_xmin,window_xmax);
3665 	  round3(newy,window_ymin,window_ymax);
3666 	  gen t=projection(evalf(tmp2,1,hp->contextptr),gen(newx,newy),hp->contextptr);
3667 	  if (is_undef(t))
3668 	    return 0;
3669 	  gen tmp3=symbolic(at_element,( (t.type<_IDNT || t.type==_VECT)?gen(makevecteur(tmp,t),_SEQ__VECT):tmp));
3670 	  tmp3=symbolic(at_sto,makevecteur(add_attributs(tmp3,couleur,contextptr),gen(autoname(hp->contextptr),hp->contextptr)));
3671 	  hp->set_gen_value(-1,tmp3,false);
3672 	  if (hp_pos<0) hp_pos=hp->children()-1;
3673 	  hp->update(hp_pos);
3674 	}
3675 	return 1;
3676       }
3677       if (event==FL_PUSH){
3678 	args_tmp=vecteur(1,tmp);
3679 	return 1;
3680       }
3681       if (event==FL_DRAG){
3682 	redraw();
3683 	if (mouse_position) mouse_position->redraw();
3684 	return 1;
3685       }
3686       return 0;
3687     }
3688     gen tmpval=remove_at_pnt(tmp.eval(1,contextptr));
3689     gen somm=symbolic(at_sommets,tmp);
3690     int npoints=1;
3691     if (!equalposcomp(nosplit_polygon_function,*function_final._FUNCptr)){
3692       if (tmpval.type==_VECT && tmpval.subtype==_GROUP__VECT)
3693 	npoints=tmpval._VECTptr->size();
3694       if (tmpval.is_symb_of_sommet(at_cercle))
3695 	npoints=gr2d?2:3;
3696     }
3697     unsigned args_size=args_tmp.size();
3698     // mode>=2
3699     if (event==FL_MOVE || event==FL_DRAG || event==FL_RELEASE || event==FL_PUSH){
3700       if (args_size<args_tmp_push_size)
3701 	args_tmp_push_size=args_size;
3702       args_tmp.erase(args_tmp.begin()+args_tmp_push_size,args_tmp.end());
3703     }
3704     unsigned new_args_size=args_tmp.size();
3705     gen tmp_push=tmp;
3706     bool swapargs=false;
3707     if (npoints==2 && (new_args_size==2 || new_args_size==1) && (function_final==at_angleat || function_final==at_angleatraw) ){
3708       // search if args_tmp[0] or args_tmp[1] is a vertex of tmp
3709       gen tmp2=remove_at_pnt(evalf(tmp,1,contextptr));
3710       gen somm=symbolic(at_sommets,tmp);
3711       if (tmp2.type==_VECT && tmp2._VECTptr->size()==2){
3712 	gen tmpa=remove_at_pnt(evalf(args_tmp[0],1,contextptr));
3713 	gen tmpb=new_args_size==2?remove_at_pnt(evalf(args_tmp[1],1,contextptr)):undef;
3714 	if (npoints==2 && tmpa==tmp2._VECTptr->front() && tmpb!=tmp2._VECTptr->back()){
3715 	  tmp=symbolic(at_at,gen(makevecteur(somm,1),_SEQ__VECT));
3716 	  npoints=1;
3717 	}
3718 	if (npoints==2 && tmpa==tmp2._VECTptr->back() && tmpb!=tmp2._VECTptr->front()){
3719 	  tmp=symbolic(at_at,gen(makevecteur(somm,0),_SEQ__VECT));
3720 	  npoints=1;
3721 	}
3722 	if (npoints==2 && tmpb==tmp2._VECTptr->front() && tmpa!=tmp2._VECTptr->back() ){
3723 	  swapargs=true;
3724 	  tmp=symbolic(at_at,gen(makevecteur(somm,1),_SEQ__VECT));
3725 	  npoints=1;
3726 	}
3727 	if (npoints==2 && tmpb==tmp2._VECTptr->back() && tmpa!=tmp2._VECTptr->front()){
3728 	  swapargs=true;
3729 	  tmp=symbolic(at_at,gen(makevecteur(somm,0),_SEQ__VECT));
3730 	  npoints=1;
3731 	}
3732       }
3733     }
3734     if (npoints+args_tmp.size()>mode)
3735       npoints=1;
3736     if (event==FL_MOVE || event==FL_DRAG || event==FL_RELEASE){
3737       if (mouse_position) mouse_position->redraw();
3738       if (args_size && args_tmp_push_size && args_push!=tmp_push){
3739 	// replace by current mouse position
3740 	if (npoints==1)
3741 	  args_tmp.push_back(tmp);
3742 	else {
3743 	  gen somm=symbolic(at_sommets,tmp);
3744 	  for (int i=0;i<npoints;++i){
3745 	    args_tmp.push_back(symbolic(at_at,gen(makevecteur(somm,i),_SEQ__VECT)));
3746 	  }
3747 	}
3748 	redraw();
3749 	if (event!=FL_RELEASE || (abs(push_i-current_i)<=5 && abs(push_j-current_j)<=5))
3750 	  return 1;
3751       }
3752     }
3753     if (event==FL_PUSH){
3754       if (swapargs)
3755 	swapgen(args_tmp[0],args_tmp[1]);
3756       args_push=tmp_push;
3757       if (npoints==1)
3758 	args_tmp.push_back(tmp);
3759       else {
3760 	for (int i=0;i<npoints;++i){
3761 	  args_tmp.push_back(symbolic(at_at,gen(makevecteur(somm,i),_SEQ__VECT)));
3762 	}
3763       }
3764       args_tmp_push_size=args_tmp.size();
3765       redraw();
3766       return 1;
3767     }
3768     if (event==FL_RELEASE){
3769       int s=args_tmp.size();
3770       args_tmp_push_size=s;
3771       int save_undo_position=hp->undo_position;
3772       if (mode>1 && s>=mode){
3773 	if (s>mode){
3774 	  args_tmp=vecteur(args_tmp.begin(),args_tmp.begin()+mode);
3775 	  s=mode;
3776 	}
3777 	gen tmp_plot;
3778 	if (in_area && function_final.type==_FUNC) {
3779 	  gen res,objname=gen(autoname(hp->contextptr),hp->contextptr);
3780 	  hp_pos=hp->children()-1;
3781 	  hp->update_pos=hp_pos;
3782 	  int pos0=hp_pos;
3783 	  unary_function_ptr * ptr=function_final._FUNCptr;
3784 	  int ifinal=mode;
3785 	  if (equalposcomp(measure_functions,*ptr))
3786 	    ifinal--;
3787 	  // first replace points in args_tmp by assignations
3788 	  for (int i=0;i<ifinal;++i){
3789 	    tmp_plot=args_tmp[i];
3790 	    if (tmp_plot.is_symb_of_sommet(at_point)){
3791 	      tmp_plot=symbolic(at_sto,makevecteur(add_attributs(tmp_plot,couleur,contextptr),objname));
3792 	      args_tmp[i]=objname;
3793 	      hp->set_gen_value(hp_pos,tmp_plot,false);
3794 	      hp->add_entry(hp_pos+1);
3795 	      ++hp_pos;
3796 	      autoname_plus_plus();
3797 	      objname=gen(autoname(hp->contextptr),hp->contextptr);
3798 	    }
3799 	  }
3800 	  vecteur argv=args_tmp;
3801 	  if (*ptr==(gr3d?at_sphere:at_cercle)){
3802 	    gen argv1;
3803 	    try {
3804 	      argv1=evalf(args_tmp.back(),1,contextptr);
3805 	      argv1=evalf_double(argv1,1,contextptr);
3806 	    }
3807 	    catch (std::runtime_error & e){
3808 	      argv1=undef;
3809 	    }
3810 	    if (argv1.is_symb_of_sommet(at_pnt) ||argv1.type==_IDNT){
3811 	      argv1=remove_at_pnt(argv1);
3812 	      if ( (argv1.type==_VECT && argv1.subtype==_POINT__VECT) || argv1.type==_CPLX || argv1.type==_IDNT)
3813 	      argv.back()=args_tmp.back()-args_tmp.front();
3814 	    }
3815 	  }
3816 	  tmp_plot=symbolic(*ptr,gen(argv,_SEQ__VECT));
3817 	  try {
3818 	    res=evalf(tmp_plot,1,hp->contextptr);
3819 	  }
3820 	  catch (std::runtime_error & err){
3821 	    res=undef;
3822 	  }
3823 	  tmp_plot=symbolic(at_sto,makevecteur(add_attributs(tmp_plot,couleur,contextptr),objname));
3824 	  hp->set_gen_value(hp_pos,tmp_plot,false);
3825 	  hp->add_entry(hp_pos+1);
3826 	  ++hp_pos;
3827 	  if (res.is_symb_of_sommet(at_pnt)){
3828 	    res=remove_at_pnt(res);
3829 	    int ns=0;
3830 	    if (res.type==_VECT && res.subtype==_GROUP__VECT && (ns=res._VECTptr->size())>2){
3831 	      vecteur l;
3832 	      if (res._VECTptr->back()==res._VECTptr->front())
3833 		--ns;
3834 	      if (function_final.type==_FUNC && equalposcomp(transformation_functions,*function_final._FUNCptr)){
3835 		vecteur argv;
3836 		gen objn,som=symbolic(at_sommets,objname);
3837 		for (int i=1;i<=ns;++i){
3838 		  tmp_plot=symbolic(at_at,gen(makevecteur(som,i-1),_SEQ__VECT));
3839 		  objn=gen(autoname(hp->contextptr)+print_INT_(i),hp->contextptr);
3840 		  argv.push_back(objn);
3841 		  hp->set_gen_value(hp_pos,symbolic(at_sto,gen(makevecteur(tmp_plot,objn),_SEQ__VECT)),false);
3842 		  hp->add_entry(hp_pos+1);
3843 		  ++hp_pos;
3844 		}
3845 		for (int i=1;i<=ns;++i){
3846 		  tmp_plot=symbolic(at_segment,makevecteur(argv[i-1],argv[i%ns]));
3847 		  hp->set_gen_value(hp_pos,symbolic(at_sto,makevecteur(add_attributs(tmp_plot,couleur,contextptr),gen(autoname(hp->contextptr)+print_INT_(ns+i),hp->contextptr))),false);
3848 		  hp->add_entry(hp_pos+1);
3849 		  ++hp_pos;
3850 		}
3851 	      }
3852 	      else {
3853 		for (int i=mode;i<ns;++i){
3854 		  tmp_plot=symb_at(
3855 				   symbolic(at_sommets,gen(autoname(hp->contextptr),hp->contextptr))
3856 				   ,i,hp->contextptr);
3857 		  gen newname=gen(autoname(hp->contextptr)+print_INT_(i),hp->contextptr);
3858 		  hp->set_gen_value(hp_pos,symbolic(at_sto,makevecteur(tmp_plot,newname)),false);
3859 		  args_tmp.push_back(newname);
3860 		  hp->add_entry(hp_pos+1);
3861 		  ++hp_pos;
3862 		}
3863 		for (int i=1;i<=ns;++i){
3864 		  tmp_plot=symbolic(at_segment,makevecteur(args_tmp[i-1],args_tmp[i%ns]));
3865 		  hp->set_gen_value(hp_pos,symbolic(at_sto,makevecteur(add_attributs(tmp_plot,couleur,contextptr),gen(autoname(hp->contextptr)+print_INT_(ns+i),hp->contextptr))),false);
3866 		  hp->add_entry(hp_pos+1);
3867 		  ++hp_pos;
3868 		}
3869 	      }
3870 	    } // if res.type==_VECT
3871 	  }
3872 	  autoname_plus_plus();
3873 	  // hp->undo_position=save_undo_position;
3874 	  hp->update(pos0);
3875 	}
3876 	args_tmp.clear();
3877 	args_tmp_push_size=0;
3878       }
3879       redraw();
3880       return 1;
3881     }
3882     return 0;
3883   }
3884 
handle(int event)3885   int Graph2d3d::handle(int event){
3886     if (no_handle)
3887       return 0;
3888     context * contextptr=hp?hp->contextptr:get_context(this);
3889 #ifdef HAVE_LIBPTHREAD
3890     // cerr << "handle lock" << '\n';
3891     int locked=pthread_mutex_trylock(&interactive_mutex);
3892     if (locked)
3893       return 0;
3894 #endif
3895     no_handle=true;
3896     bool b=io_graph(contextptr);
3897     io_graph(false,contextptr);
3898     int res=in_handle(event);
3899     io_graph(b,contextptr);
3900     no_handle=false;
3901 #ifdef HAVE_LIBPTHREAD
3902     pthread_mutex_unlock(&interactive_mutex);
3903     // cerr << "handle unlock" << '\n';
3904 #endif
3905     return res;
3906   }
3907 
handle_mouse(int event)3908   int Graph2d3d::handle_mouse(int event){
3909     if (event==FL_MOVE || event==FL_ENTER || event==FL_LEAVE){
3910       if (mouse_position) mouse_position->redraw();
3911       if (event==FL_MOVE && hp && show_mouse_on_object){
3912 	double newx,newy,newz;
3913 	Graph3d * gr3d = dynamic_cast<Graph3d *>(this);
3914 	find_xyz(Fl::event_x()-(gr3d?0:x()),Fl::event_y()-(gr3d?0:y()),current_depth,newx,newy,newz);
3915 	int pos=-1;
3916 	gen orig;
3917 	gen res=geometry_round(newx,newy,newz,find_eps(),orig,pos);
3918 	set_cursor(this, pos>=0?FL_CURSOR_HAND:FL_CURSOR_ARROW);
3919       }
3920       else
3921 	set_cursor(this, FL_CURSOR_ARROW);
3922       return 1;
3923     }
3924     return 0;
3925   }
3926 
handle_keyboard(int event)3927   int Graph2d3d::handle_keyboard(int event){
3928     if (event==FL_KEYBOARD){
3929       // Should bring this event to the current input in the parent() group
3930       switch (Fl::event_key()){
3931       case FL_Escape: case FL_BackSpace: case FL_Tab: case FL_Enter:
3932       case FL_Print: case FL_Scroll_Lock: case FL_Pause: case FL_Insert:
3933       case FL_Home: case FL_Delete: case FL_End:
3934       case FL_Shift_L: case FL_Shift_R: case FL_Control_L:
3935       case FL_Control_R: case FL_Caps_Lock: case FL_Alt_L: case FL_Alt_R:
3936       case FL_Meta_L: case FL_Meta_R: case FL_Menu: case FL_Num_Lock:
3937       case FL_KP_Enter:
3938 	return 1;
3939       case FL_Left:
3940 	left((window_xmax-window_xmin)/10);
3941 	return 1;
3942       case FL_Up:
3943 	up((window_ymax-window_ymin)/10);
3944 	return 1;
3945       case FL_Right:
3946 	right((window_xmax-window_xmin)/10);
3947 	return 1;
3948       case FL_Down:
3949 	down((window_ymax-window_ymin)/10);
3950 	return 1;
3951       case FL_Page_Up:
3952 	up_z((window_zmax-window_zmin)/10);
3953 	return 1;
3954       case FL_Page_Down:
3955 	down_z((window_zmax-window_zmin)/10);
3956 	return 1;
3957       default:
3958 	char ch=Fl::event_text()?Fl::event_text()[0]:0;
3959 	switch (ch){
3960 	case '-':
3961 	  zoom(1.414);
3962 	  return 1;
3963 	case '+':
3964 	  zoom(0.707);
3965 	  return 1;
3966 	case 'A': case 'a':
3967 	  autoscale(false);
3968 	  return 1;
3969 	case 'V': case 'v':
3970 	  autoscale(true);
3971 	  return 1;
3972 	case 'R': case 'r':
3973 	  oxyz_rotate(this,rotanim_type,rotanim_nstep,rotanim_tstep,rotanim_danim,rotanim_rx,rotanim_ry,rotanim_rz);
3974 	  return 1;
3975 	case 'P': case 'p':
3976 	  paused=!paused;
3977 	  return 1;
3978 	case 'N': case 'n': case 'F': case 'f':
3979 	  animation_instructions_pos++;
3980 	  redraw();
3981 	  return 1;
3982 	case 'B': case 'b':
3983 	  animation_instructions_pos--;
3984 	  redraw();
3985 	  return 1;
3986 	case 'C': case 'c': /* screen capture */
3987 	  if (Graph3d * gr3 = dynamic_cast<Graph3d *>(this)){
3988 	    char * filename = file_chooser(gettext("Export to PNG file"),"*.png","session.png");
3989 	    if(!filename) return 1;
3990 	    gr3->opengl2png(filename);
3991 	    return 1;
3992 	  }
3993 	}
3994       }
3995     }
3996     return 0;
3997   }
3998 
in_handle(int event)3999   int Graph2d3d::in_handle(int event){
4000     int res=handle_keyboard(event);
4001     return res?res:handle_mouse(event);
4002   }
4003 
selection2vecteur(const vector<int> & v)4004   vecteur Graph2d3d::selection2vecteur(const vector<int> & v){
4005     int n=v.size();
4006     vecteur res(n);
4007     for (int i=0;i<n;++i){
4008       res[i]=plot_instructions[v[i]];
4009     }
4010     return res;
4011   }
4012 
findfirstclosedcurve(const vecteur & v)4013   int findfirstclosedcurve(const vecteur & v){
4014     int s=v.size();
4015     for (int i=0;i<s;++i){
4016       gen g=remove_at_pnt(v[i]);
4017       if (g.is_symb_of_sommet(at_cercle))
4018 	return i;
4019       if (g.type==_VECT && g.subtype==_GROUP__VECT){
4020 	vecteur & w=*g._VECTptr;
4021 	if (!w.empty() && w.front()==w.back())
4022 	  return i;
4023       }
4024     }
4025     return -1;
4026   }
4027 
4028   // find nearest point of x+i*y, returns position in history and either
4029   // a numeric value or the point name
geometry_round(double x,double y,double z,double eps,gen & original,int & pos,bool selectfirstlevel,bool setscroller)4030   gen Graph2d3d::geometry_round(double x,double y,double z,double eps,gen & original,int & pos,bool selectfirstlevel,bool setscroller) {
4031     if (!hp)
4032       return undef;
4033     context * contextptr=hp?hp->contextptr:get_context(this);
4034     gen tmp;
4035     pos=-1;
4036     if (block_signal || is_context_busy(contextptr))
4037       return undef;
4038     geometry_round(x,y,z,eps,tmp,contextptr);
4039     if (selected.empty())
4040       return tmp;
4041     if (function_final==at_areaatraw || function_final==at_areaat || function_final==at_perimeteratraw || function_final==at_perimeterat){
4042       int p=findfirstclosedcurve(selection2vecteur(selected));
4043       if (p>0){
4044 	pos=p;
4045       }
4046     }
4047     if (pos==-1){
4048       if (selectfirstlevel){
4049 	sort(selected.begin(),selected.end());
4050 	// patch so that we move element and not the curve
4051 	int p=findfirstpoint(selection2vecteur(selected));
4052 	if (p>0){
4053 	  /*
4054 	  gen g=hp->parse(selected[p]);
4055 	  if (g.is_symb_of_sommet(at_sto) && g._SYMBptr->feuille.type==_VECT ){
4056 	    vecteur & v = *g._SYMBptr->feuille._VECTptr;
4057 	    if (v.size()>1 && v[0].is_symb_of_sommet(at_element))
4058 	      pos=p;
4059 	  }
4060 	  */
4061 	  pos=p;
4062 	}
4063       }
4064       else
4065 	pos=findfirstpoint(selection2vecteur(selected));
4066     }
4067     gen g=hp->parse( (pos<0)?(pos=selected.front()):(pos=selected[pos]) );
4068     if (pos>=0 && pos<hp->children()){
4069       hp->_sel_begin=hp->_sel_end=pos;
4070       if (setscroller)
4071 	hp->set_scroller(dynamic_cast<Fl_Group *>(hp->child(pos)));
4072     }
4073     if (g.is_symb_of_sommet(at_plus) && g._SYMBptr->feuille.type==_VECT && !g._SYMBptr->feuille._VECTptr->empty())
4074       g=g._SYMBptr->feuille._VECTptr->front();
4075     if (g.is_symb_of_sommet(at_sto) && g._SYMBptr->feuille.type==_VECT ){
4076       vecteur & v = *g._SYMBptr->feuille._VECTptr;
4077       if (v.size()==2){
4078 	original = v[0];
4079 	tmp = v[1];
4080 	if (tmp.type==_IDNT){
4081 	  gen valeur=protecteval(original,1,contextptr);
4082 	  if (valeur.is_symb_of_sommet(at_pnt)){
4083 	    gen & valf = valeur._SYMBptr->feuille;
4084 	    if (valf.type==_VECT){
4085 	      vecteur & valv = *valf._VECTptr;
4086 	      int s=v.size();
4087 	      if (s>1){
4088 		gen valv1=valv[1];
4089 		if (valv1.type==_VECT && valv1._VECTptr->size()>2){
4090 		  tmp=symbolic(at_extract_measure,v[1]);
4091 		}
4092 	      }
4093 	    }
4094 	  }
4095 	}
4096       }
4097     }
4098     return tmp;
4099   }
4100 
geometry_round(double x,double y,double z,double eps,gen & tmp,GIAC_CONTEXT)4101   void Graph2d3d::geometry_round(double x,double y,double z,double eps,gen & tmp,GIAC_CONTEXT) {
4102   }
4103 
geometry_round(double x,double y,double z,double eps,gen & tmp,GIAC_CONTEXT)4104   void Graph2d::geometry_round(double x,double y,double z,double eps,gen & tmp,GIAC_CONTEXT) {
4105     tmp= geometry_round_numeric(x,y,eps,approx);
4106     try {
4107       selected=nearest_point(plot_instructions,geometry_round_numeric(x,y,eps,true),eps,contextptr);
4108       // bug bonux: when a figure is saved, plot_instructions is saved
4109       // if there are sequences in plot_instructions
4110       // they are not put back in an individual level
4111       while (!selected.empty() && selected.back()>=hp->children())
4112 	selected.pop_back();
4113     } catch (...){
4114     }
4115   }
4116 
int2color(int couleur_)4117   gen int2color(int couleur_){
4118     gen col;
4119     if (couleur_){
4120       gen tmp;
4121       int val;
4122       vecteur colv;
4123       if ( (val=(couleur_ & 0x0000ffff))){
4124 	tmp=val;
4125 	tmp.subtype=_INT_COLOR;
4126 	colv.push_back(tmp);
4127       }
4128       if ((val =(couleur_ & 0x00070000))){
4129 	tmp=val;
4130 	tmp.subtype=_INT_COLOR;
4131 	colv.push_back(tmp);
4132       }
4133       if ((val =(couleur_ & 0x00380000))){
4134 	tmp=val;
4135 	tmp.subtype=_INT_COLOR;
4136 	colv.push_back(tmp);
4137       }
4138       if ((val =(couleur_ & 0x01c00000))){
4139 	tmp=val;
4140 	tmp.subtype=_INT_COLOR;
4141 	colv.push_back(tmp);
4142       }
4143       if ((val =(couleur_ & 0x0e000000))){
4144 	tmp=val;
4145 	tmp.subtype=_INT_COLOR;
4146 	colv.push_back(tmp);
4147       }
4148       if ((val =(couleur_ & 0x30000000))){
4149 	tmp=val;
4150 	tmp.subtype=_INT_COLOR;
4151 	colv.push_back(tmp);
4152       }
4153       if ((val =(couleur_ & 0x40000000))){
4154 	tmp=val;
4155 	tmp.subtype=_INT_COLOR;
4156 	colv.push_back(tmp);
4157       }
4158       if ((val =(couleur_ & 0x80000000))){
4159 	tmp=val;
4160 	tmp.subtype=_INT_COLOR;
4161 	colv.push_back(tmp);
4162       }
4163       if (colv.size()==1)
4164 	col=colv.front();
4165       else
4166 	col=symbolic(at_plus,gen(colv,_SEQ__VECT));
4167     }
4168     return col;
4169   }
4170 
print_color(int couleur)4171   std::string print_color(int couleur){
4172     return int2color(couleur).print(context0);
4173   }
4174 
add_attributs(const giac::gen & g,int couleur_,GIAC_CONTEXT)4175   giac::gen add_attributs(const giac::gen & g,int couleur_,GIAC_CONTEXT) {
4176     if (g.type!=_SYMB)
4177       return g;
4178     gen & f=g._SYMBptr->feuille;
4179     if (g._SYMBptr->sommet==at_couleur && f.type==_VECT && !f._VECTptr->empty()){
4180       gen col=couleur_;
4181       col.subtype=_INT_COLOR;
4182       vecteur v(*f._VECTptr);
4183       v.back()=col;
4184       return symbolic(at_couleur,gen(v,_SEQ__VECT));
4185     }
4186     if (couleur_==default_color(contextptr))
4187       return g;
4188     if (g._SYMBptr->sommet==at_of){
4189       gen col=couleur_;
4190       col.subtype=_INT_COLOR;
4191       return symbolic(at_couleur,gen(makevecteur(g,col),_SEQ__VECT));
4192     }
4193     vecteur v =gen2vecteur(f);
4194     gen col=int2color(couleur_);
4195     v.push_back(symbolic(at_equal,gen(makevecteur(at_display,col),_SEQ__VECT)));
4196     return symbolic(g._SYMBptr->sommet,(v.size()==1 && f.type!=_VECT)?f:gen(v,f.type==_VECT?f.subtype:_SEQ__VECT));
4197   }
4198 
set_mode(const giac::gen & f_tmp,const giac::gen & f_final,int m)4199   void Graph2d3d::set_mode(const giac::gen & f_tmp,const giac::gen & f_final,int m){
4200     if (mode>=-1){
4201       pushed=false;
4202       moving=moving_frame=false;
4203       history_pos=-1;
4204       mode=m;
4205       function_final=f_final;
4206       function_tmp=f_tmp;
4207       args_tmp.clear();
4208     }
4209   }
4210 
cb_set_mode(Fl_Widget * m,const gen & f_tmp,const gen & f_final,int mode,const string & help)4211   void cb_set_mode(Fl_Widget * m ,const gen & f_tmp,const gen & f_final,int mode,const string & help){
4212     static string modestr;
4213     static bool asked=false;
4214     Figure * f=find_figure(m);
4215     if (f && f->geo){
4216       if (!asked && mode==0 && !f->geo->approx){
4217 	int i=fl_ask("%s","Dynamic geometry works faster in approx mode. Drag in approx mode?");
4218 	if (i)
4219 	  f->geo->approx=true;
4220 	asked=true;
4221       }
4222       if (dynamic_cast<Geo2d *>(f->geo) || dynamic_cast<Geo3d *>(f->geo)){
4223 	f->geo->selected.clear();
4224 	f->geo->redraw();
4225 	f->geo->handle(FL_FOCUS);
4226 	context * contextptr=f->geo->hp?f->geo->hp->contextptr:0;
4227 	f->geo->set_mode(f_tmp,f_final,mode);
4228 	f->geo->args_help.clear();
4229 	if (mode!=0 && mode!=255){
4230 	  int oldmode=calc_mode(contextptr);
4231 	  calc_mode(0,contextptr);
4232 	  gen g(help,contextptr);
4233 	  calc_mode(oldmode,contextptr);
4234 	  if (g.type==_VECT){
4235 	    const_iterateur it = g._VECTptr->begin(),itend=g._VECTptr->end();
4236 	    for (;it!=itend;++it)
4237 	      f->geo->args_help.push_back(it->print(contextptr));
4238 	  }
4239 	  else
4240 	    f->geo->args_help.push_back(g.print(contextptr));
4241 	}
4242       }
4243       if (mode==255)
4244 	modestr=gettext("Frame");
4245       else
4246 	modestr=mode?gen2string(f_final):gettext("Pointer");
4247       f->mode->value(modestr.c_str());
4248     }
4249   }
4250 
Geo2d(int x,int y,int w,int h,History_Pack * _hp,const char * l)4251   Geo2d::Geo2d(int x,int y,int w,int h,History_Pack * _hp,const char * l): Graph2d(x,y,w,h,l) {
4252     orthonormalize();
4253     hp=_hp?_hp:geo_find_history_pack(this);
4254     if (hp)
4255       show_mouse_on_object=true;
4256   }
4257 
in_handle(int event)4258   int Geo2d::in_handle(int event){
4259     if (!event)
4260       return 1;
4261     if (!hp)
4262       hp=geo_find_history_pack(this);
4263     // cerr << event << " " << mode << '\n';
4264     int res=common_in_handle(event);
4265     if (Fl::event_button()==FL_RIGHT_MOUSE && res && mode==255)
4266       return res; // right click desactivated
4267     if (event==FL_UNFOCUS){
4268       return 1;
4269     }
4270     if (event==FL_FOCUS){
4271       Fl::focus(this);
4272       return 1;
4273     }
4274     if (int gres=geo_handle(event))
4275       return gres;
4276     // event not handeld by geometry
4277     return res;
4278   }
4279 
fltk_point(int deltax,int deltay,int i0,int j0,int epaisseur_point,int type_point)4280   void fltk_point(int deltax,int deltay,int i0,int j0,int epaisseur_point,int type_point){
4281     fl_line_style(FL_SOLID,epaisseur_point-1,0);
4282     switch (type_point){
4283     case 1: // losange
4284       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0-epaisseur_point);
4285       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0);
4286       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0+epaisseur_point);
4287       fl_line(deltax+i0,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0);
4288       break;
4289     case 2: // croix verticale
4290       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0,deltay+j0+epaisseur_point);
4291       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0);
4292       break;
4293     case 3: // carre
4294       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0-epaisseur_point,deltay+j0+epaisseur_point);
4295       fl_line(deltax+i0+epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point);
4296       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0-epaisseur_point);
4297       fl_line(deltax+i0-epaisseur_point,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point);
4298       break;
4299     case 5: // triangle
4300       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0-epaisseur_point);
4301       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0);
4302       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0);
4303       break;
4304     case 7: // point
4305       if (epaisseur_point>2)
4306 	fl_arc(deltax+i0-(epaisseur_point-1),deltay+j0-(epaisseur_point-1),2*(epaisseur_point-1),2*(epaisseur_point-1),0,360);
4307       else
4308 	fl_line(deltax+i0,deltay+j0,deltax+i0+1,deltay+j0);
4309       break;
4310     case 6: // etoile
4311       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0);
4312       // no break to add the following lines
4313     case 0: // 0 croix diagonale
4314       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point);
4315       fl_line(deltax+i0-epaisseur_point,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0-epaisseur_point);
4316       break;
4317     default: // 4 nothing drawn
4318       break;
4319     }
4320     fl_line_style(0);
4321   }
4322 
draw()4323   void Geo2d::draw(){
4324     if (!hp)
4325       hp=geo_find_history_pack(this);
4326     context * contextptr = hp?hp->contextptr:0;
4327     int locked=0;
4328 #ifdef HAVE_LIBPTHREAD
4329     // cerr << "geo2d draw lock" << '\n';
4330     locked=pthread_mutex_trylock(&interactive_mutex);
4331 #endif
4332     bool b,block;
4333     if (!locked){
4334       b=io_graph(contextptr);
4335       io_graph(contextptr)=false;
4336       block=block_signal;
4337       block_signal=true;
4338     }
4339     int clip_x,clip_y,clip_w,clip_h;
4340     // cerr << "geo2d draw block signal " << this << '\n';
4341     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
4342     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
4343     int vertical_pixels;
4344     in_draw(clip_x,clip_y,clip_w,clip_h,vertical_pixels);
4345     int horizontal_pixels=w()-(show_axes?int(ylegende*labelsize()):0);
4346     int deltax=x(),deltay=y();
4347     if (mode<255 && abs_calc_mode(contextptr)==38){
4348       fl_color(FL_CYAN);
4349       fltk_point(deltax,deltay,current_i,current_j,cursor_point_type,cursor_point_type);
4350     }
4351     // Draw mouse drag
4352     if ( pushed && !waiting_click &&(current_i>=0 && current_i<=horizontal_pixels) && (current_j>=0 && current_j <=vertical_pixels) && (user_screen || (push_i!=current_i) || (push_j!=current_j))){
4353       fl_color(FL_RED);
4354       if ( (mode==255 && Fl::event_button()==FL_RIGHT_MOUSE) || (mode==0 && !moving && !moving_frame) )
4355 	check_fl_rect(deltax+min(push_i,current_i),deltay+min(push_j,current_j),absint(current_i-push_i),absint(current_j-push_j),clip_x,clip_y,clip_w,clip_h,0,0);
4356       else
4357 	check_fl_line(deltax+push_i,deltay+push_j,deltax+current_i,deltay+current_j,clip_x,clip_y,clip_w,clip_h,0,0);
4358     }
4359     fl_pop_clip();
4360     ++animation_instructions_pos;
4361     if (!locked){
4362       block_signal=block;
4363       // cerr << "geo2d draw unblock signal " << this << '\n';
4364       io_graph(contextptr)=b;
4365 #ifdef HAVE_LIBPTHREAD
4366       pthread_mutex_unlock(&interactive_mutex);
4367     // cerr << "geo2d draw unlock" << '\n';
4368 #endif
4369     }
4370   }
4371 
swapint(int & i0,int & i1)4372   inline void swapint(int & i0,int & i1){
4373     int tmp=i0;
4374     i0=i1;
4375     i1=tmp;
4376   }
4377 
check_fl_draw(const char * ch,int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j)4378   void check_fl_draw(const char * ch,int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j){
4379     /* int n=fl_size();
4380        if (j0>=jmin-n && j0<=jmin+dj+n) */
4381     // cerr << i0 << " " << j0 << '\n';
4382     if (strlen(ch)>2000)
4383       fl_draw("String too long for display",i0+delta_i,j0+delta_j);
4384     else
4385       fl_draw(ch,i0+delta_i,j0+delta_j);
4386   }
4387 
check_fl_point(int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j)4388   void check_fl_point(int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j){
4389     /* if (i0>=imin && i0<=imin+di && j0>=jmin && j0<=jmin+dj) */
4390       fl_point(i0+delta_i,j0+delta_j);
4391   }
4392 
check_fl_rect(int i0,int j0,int i1,int j1,int imin,int jmin,int di,int dj,int delta_i,int delta_j)4393   void check_fl_rect(int i0,int j0,int i1,int j1,int imin,int jmin,int di,int dj,int delta_i,int delta_j){
4394     /*    bool clipped=false;
4395     if (imin>i0 || jmin>j0){
4396       check_fl_line(i0,j0,i0+i1,j0,imin,jmin,di,dj,delta_i,delta_j);
4397       check_fl_line(i0,j0,i0,j0+j1,imin,jmin,di,dj,delta_i,delta_j);
4398       check_fl_line(i0,j0+j1,i0+i1,j0+j1,imin,jmin,di,dj,delta_i,delta_j);
4399       check_fl_line(i0+i1,j0,i0+i1,j0+j1,imin,jmin,di,dj,delta_i,delta_j);
4400     }
4401     else
4402       fl_rect(i0+delta_i,j0+delta_j,min(i1,di),min(j1,dj));
4403     */
4404     fl_rect(i0+delta_i,j0+delta_j,i1,j1);
4405   }
4406 
check_fl_rectf(int x,int y,int w,int h,int imin,int jmin,int di,int dj,int delta_i,int delta_j)4407   void check_fl_rectf(int x,int y,int w,int h,int imin,int jmin,int di,int dj,int delta_i,int delta_j){
4408     /*    if (x<imin){
4409       w -= (imin-x); // di -= (imin-x);
4410       x=imin;
4411     }
4412     if (y<jmin){
4413       h -= (jmin-y); // dj -= (jmin-y);
4414       y=jmin;
4415     }
4416     if (w<=0 || di<=0 || h<=0 || dj<=0)
4417       return ;
4418     fl_rectf(x+delta_i,y+delta_j,min(w,di),min(h,dj));
4419     */
4420     fl_rectf(x+delta_i,y+delta_j,w,h);
4421   }
4422 
4423   // Calls fl_line, checking with bounds
check_fl_line(int i0,int j0,int i1,int j1,int imin,int jmin,int di,int dj,int delta_i,int delta_j)4424   void check_fl_line(int i0,int j0,int i1,int j1,int imin,int jmin,int di,int dj,int delta_i,int delta_j){
4425     /* int imax=imin+di,jmax=jmin+dj;
4426     if (i0>i1){
4427       swapint(i0,i1);
4428       swapint(j0,j1);
4429     }
4430     if (i0>=imax || i1<=imin)
4431       return;
4432     if (i0!=i1){
4433       // Compute line slope
4434       double m=(j1-j0)/double(i1-i0);
4435       if (i0<imin){ // replace i0 by imin, compute corresp. j0
4436 	j0 += int(floor((imin-i0)*m+.5));
4437 	i0 = imin;
4438       }
4439       if (i1>imax){
4440 	j1 += int(floor((imax-i1)*m+.5));
4441 	i1 = imax;
4442       }
4443     }
4444     if (j0>j1){
4445       if (j1>=jmax || j0<=jmin)
4446 	return;
4447       // Compute line slope
4448       double m=(i1-i0)/double(j1-j0);
4449       if (j0>jmax){
4450 	i0 += int(floor((jmax-j0)*m+.5));
4451 	j0 = jmax;
4452       }
4453       if (j1<jmin){
4454 	i1 += int(floor((jmin-j1)*m+.5));
4455 	j1 = jmin;
4456       }
4457     }
4458     else {
4459       if (j0>=jmax || j1<=jmin)
4460 	return;
4461       if (j0!=j1){
4462 	// Compute line slope
4463 	double m=(i1-i0)/double(j1-j0);
4464 	if (j0<jmin){
4465 	  i0 += int(floor((jmin-j0)*m+.5));
4466 	  j0 = jmin;
4467 	}
4468 	if (j1>jmax){
4469 	  i1 += int(floor((jmax-j1)*m+.5));
4470 	  j1 = jmax;
4471 	}
4472       }
4473       } */
4474     fl_line(i0+delta_i,j0+delta_j,i1+delta_i,j1+delta_j);
4475   }
4476 
4477   int logplot_points=20;
4478 
checklog_fl_line(double i0,double j0,double i1,double j1,double deltax,double deltay,bool logx,bool logy,double window_xmin,double x_scale,double window_ymax,double y_scale)4479   void checklog_fl_line(double i0,double j0,double i1,double j1,double deltax,double deltay,bool logx,bool logy,double window_xmin,double x_scale,double window_ymax,double y_scale){
4480     if (!logx && !logy){
4481       fl_line(round(i0+deltax),round(j0+deltay),round(i1+deltax),round(j1+deltay));
4482       return;
4483     }
4484     // interpolate (i0,j0)->(i1,j1)
4485     // if log enabled i0=(log10(x0)-window_xmin)*x_scale -> x0=pow10(i0/x_scale+window_xmin)
4486     // j0=(window_ymax-log10(y1))*y_scale -> y1=pow10(window_ymax-j0/y_scale)
4487     if (logx && logy){
4488       double prevx=i0,prevy=j0,curx,cury;
4489       double I0=pow10(i0/x_scale+window_xmin),I1=pow10(i1/x_scale+window_xmin),
4490 	J0=pow10(window_ymax-j0/y_scale),J1=pow10(window_ymax-j1/y_scale);
4491       for (int i=1;i<logplot_points;++i){
4492 	double t=double(i)/logplot_points;
4493 	curx=(log10(I0+t*(I1-I0))-window_xmin)*x_scale;
4494 	cury=(window_ymax-log10(J0+t*(J1-J0)))*y_scale;
4495 	fl_line(round(prevx+deltax),round(prevy+deltay),round(curx+deltax),round(cury+deltay));
4496 	prevx=curx; prevy=cury;
4497       }
4498       return;
4499     }
4500     if (logy){
4501       double prevx=i0,prevy=j0,curx,cury;
4502       double J0=pow10(window_ymax-j0/y_scale),J1=pow10(window_ymax-j1/y_scale);
4503       for (int i=1;i<logplot_points;++i){
4504 	double t=double(i)/logplot_points;
4505 	curx=i0+t*(i1-i0);
4506 	cury=(window_ymax-log10(J0+t*(J1-J0)))*y_scale;
4507 	fl_line(round(prevx+deltax),round(prevy+deltay),round(curx+deltax),round(cury+deltay));
4508 	prevx=curx; prevy=cury;
4509       }
4510       return;
4511     }
4512     // logx
4513     double prevx=i0,prevy=j0,curx,cury;
4514     double I0=pow10(i0/x_scale+window_xmin),I1=pow10(i1/x_scale+window_xmin);
4515     for (int i=1;i<logplot_points;++i){
4516       double t=double(i)/logplot_points;
4517       curx=(log10(I0+t*(I1-I0))-window_xmin)*x_scale;
4518       cury=j0+t*(j1-j0);
4519       fl_line(round(prevx+deltax),round(prevy+deltay),round(curx+deltax),round(cury+deltay));
4520       prevx=curx; prevy=cury;
4521     }
4522   }
4523 
find_dxdy(const string & legendes,int labelpos,int labelsize,int & dx,int & dy)4524   void find_dxdy(const string & legendes,int labelpos,int labelsize,int & dx,int & dy){
4525     int l=int(fl_width(legendes.c_str()));
4526     dx=3;
4527     dy=1;
4528     switch (labelpos){
4529     case 1:
4530       dx=-l-3;
4531       break;
4532     case 2:
4533       dx=-l-3;
4534       dy=labelsize-2;
4535       break;
4536     case 3:
4537       dy=labelsize-2;
4538       break;
4539     }
4540   }
4541 
draw_legende(const vecteur & f,int i0,int j0,int labelpos,const Graph2d * iptr,int clip_x,int clip_y,int clip_w,int clip_h,int deltax,int deltay)4542   void draw_legende(const vecteur & f,int i0,int j0,int labelpos,const Graph2d * iptr,int clip_x,int clip_y,int clip_w,int clip_h,int deltax,int deltay){
4543     if (f.empty() ||!iptr->show_names )
4544       return;
4545     string legendes;
4546     const context * contextptr = get_context(iptr);
4547     if (f[0].is_symb_of_sommet(at_curve)){
4548       gen & f0=f[0]._SYMBptr->feuille;
4549       if (f0.type==_VECT && !f0._VECTptr->empty()){
4550 	gen & f1 = f0._VECTptr->front();
4551 	if (f1.type==_VECT && f1._VECTptr->size()>4 && (!is_zero((*f1._VECTptr)[4]) || (iptr->show_names & 2)) ){
4552 	  gen legende=f1._VECTptr->front();
4553 	  gen var=(*f1._VECTptr)[1];
4554 	  gen r=re(legende,contextptr),i=im(legende,contextptr),a,b;
4555 	  if (var.type==_IDNT && is_linear_wrt(r,*var._IDNTptr,a,b,contextptr)){
4556 	    i=subst(i,var,(var-b)/a,false,contextptr);
4557 	    legendes=i.print(contextptr);
4558 	  }
4559 	  else
4560 	    legendes=r.print(contextptr)+","+i.print(contextptr);
4561 	  if (legendes.size()>18){
4562 	    if (legendes.size()>30)
4563 	      legendes="";
4564 	    else
4565 	      legendes=legendes.substr(0,16)+"...";
4566 	  }
4567 	}
4568       }
4569     }
4570     if (f.size()>2)
4571       legendes=gen2string(f[2])+(legendes.empty()?"":":")+legendes;
4572     if (legendes.empty())
4573       return;
4574     if (abs_calc_mode(contextptr)==38 && legendes.size()>1 && legendes[0]=='G')
4575       legendes=legendes.substr(1,legendes.size()-1);
4576     fl_font(cst_greek_translate(legendes),iptr->labelsize());
4577     int dx=3,dy=1;
4578     find_dxdy(legendes,labelpos,iptr->labelsize(),dx,dy);
4579     check_fl_draw(legendes.c_str(),iptr->x()+i0+dx,iptr->y()+j0+dy,clip_x,clip_y,clip_w,clip_h,deltax,deltay);
4580   }
4581 
petite_fleche(double i1,double j1,double dx,double dy,int deltax,int deltay,int width)4582   void petite_fleche(double i1,double j1,double dx,double dy,int deltax,int deltay,int width){
4583     double dxy=std::sqrt(dx*dx+dy*dy);
4584     if (dxy){
4585       dxy/=max(2,min(5,int(dxy/10)))+width;
4586       dx/=dxy;
4587       dy/=dxy;
4588       double dxp=-dy,dyp=dx; // perpendicular
4589       dx*=std::sqrt(3.0);
4590       dy*=sqrt(3.0);
4591       fl_polygon(round(i1)+deltax,round(j1)+deltay,round(i1+dx+dxp)+deltax,round(j1+dy+dyp)+deltay,round(i1+dx-dxp)+deltax,round(j1+dy-dyp)+deltay);
4592     }
4593   }
4594 
draw_filled_polygon(const vector<vector<int>> & v)4595   void draw_filled_polygon(const vector< vector<int> > & v){
4596     if (v.empty()) return;
4597     fl_push_matrix();
4598     fl_begin_complex_polygon();
4599     for (size_t i=0;i<v.size();++i){
4600       fl_vertex(v[i][0],v[i][1]);
4601     }
4602     if (v.back()!=v.front())
4603       fl_vertex(v[0][0],v[0][1]);
4604     fl_end_complex_polygon();
4605     fl_pop_matrix(); // Restore initial matrix
4606   }
4607 
fl_pie_seg(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,bool segment=false)4608   void fl_pie_seg(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,bool segment=false){
4609     if (!segment){
4610       fl_pie(x,y,rx,ry,theta1_deg,theta2_deg);
4611       return;
4612     }
4613     // approximation by a filled polygon
4614     // points: (x,y), (x+rx*cos(theta)/2,y+ry*sin(theta)/2) theta=theta1..theta2
4615     while (theta2_deg<theta1_deg)
4616       theta2_deg+=360;
4617     if (theta2_deg-theta1_deg>=360){
4618       theta1_deg=0;
4619       theta2_deg=360;
4620     }
4621     int N0=theta2_deg-theta1_deg+1;
4622     // reduce N if rx or ry is small
4623     double red=double(rx)/1024*double(ry)/768;
4624     if (red>1) red=1;
4625     if (red<0.1) red=0.1;
4626     int N=red*N0;
4627     if (N<5)
4628       N=N0>5?5:N0;
4629     if (N<2)
4630       N=2;
4631     vector< vector<int> > v(segment?N+1:N+2,vector<int>(2));
4632     x += rx/2;
4633     y += ry/2;
4634     int i=0;
4635     if (!segment){
4636       v[0][0]=x;
4637       v[0][1]=y;
4638       ++i;
4639     }
4640     double theta=theta1_deg*M_PI/180;
4641     double thetastep=(theta2_deg-theta1_deg)*M_PI/(180*(N-1));
4642     for (;i<v.size()-1;++i){
4643       v[i][0]=int(x+rx*std::cos(theta)/2+.5);
4644       v[i][1]=int(y-ry*std::sin(theta)/2+.5); // y is inverted
4645       theta += thetastep;
4646     }
4647     v.back()=v.front();
4648     draw_filled_polygon(v);
4649   }
4650 
4651   // helper for Graph2d::draw method
4652   // plot_i is the position we are drawing in plot_instructions
4653   // f is the vector of arguments and s is the function: we draw s(f)
4654   // legende_x is the x position in pixels of the parameter subwindow
4655   // parameter_y is the current y position for parameter drawing
4656   // x_scale and y_scale are the current scales
4657   // horizontal_pixels and vertical_pixels the size of the window
fltk_draw(Graph2d & Mon_image,int plot_i,const gen & g,double x_scale,double y_scale,int clip_x,int clip_y,int clip_w,int clip_h)4658   void fltk_draw(Graph2d & Mon_image,int plot_i,const gen & g,double x_scale,double y_scale,int clip_x,int clip_y,int clip_w,int clip_h){
4659     int deltax=Mon_image.x(),deltay=Mon_image.y();
4660     History_Pack * hp =get_history_pack(&Mon_image);
4661     context * contextptr=hp?hp->contextptr:get_context(hp);
4662     if (g.type==_VECT){
4663       vecteur v = merge_pixon(*g._VECTptr);
4664       const_iterateur it=v.begin(),itend=v.end();
4665       for (;it!=itend;++it){
4666 	fltk_draw(Mon_image,plot_i,*it,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
4667 	fl_line_style(0); // back to default line style
4668       } // end for it
4669     }
4670     if (g.type!=_SYMB)
4671       return;
4672     unary_function_ptr s=g._SYMBptr->sommet;
4673     if (s==at_animation){
4674       fltk_draw(Mon_image,plot_i,get_animation_pnt(g,Mon_image.animation_instructions_pos),x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
4675       return;
4676     }
4677     if (g._SYMBptr->feuille.type!=_VECT)
4678       return;
4679     vecteur f=*g._SYMBptr->feuille._VECTptr;
4680     int mxw=Mon_image.w(),myw=Mon_image.h()-(Mon_image.show_axes?(Mon_image.title.empty()?1:2):0)*Mon_image.labelsize();
4681     double i0,j0,i0save,j0save,i1,j1;
4682     int fs=f.size();
4683     if ((fs==4) && (s==at_parameter)){
4684       return ;
4685     }
4686     string the_legend;
4687     vecteur style(get_style(f,the_legend));
4688     int styles=style.size();
4689     // color
4690     int ensemble_attributs = style.front().val;
4691     bool hidden_name = false;
4692     if (style.front().type==_ZINT){
4693       ensemble_attributs = mpz_get_si(*style.front()._ZINTptr);
4694       hidden_name=true;
4695     }
4696     else
4697       hidden_name=ensemble_attributs<0;
4698     int width           =(ensemble_attributs & 0x00070000) >> 16; // 3 bits
4699     int epaisseur_point =(ensemble_attributs & 0x00380000) >> 19; // 3 bits
4700     int type_line       =(ensemble_attributs & 0x01c00000) >> 22; // 3 bits
4701     if (type_line>4)
4702       type_line=(type_line-4)<<8;
4703     int type_point      =(ensemble_attributs & 0x0e000000) >> 25; // 3 bits
4704     int labelpos        =(ensemble_attributs & 0x30000000) >> 28; // 2 bits
4705     bool fill_polygon   =(ensemble_attributs & 0x40000000) >> 30;
4706     int couleur         =(ensemble_attributs & 0x0000ffff);
4707     epaisseur_point += 2;
4708     std::pair<Fl_Image *,Fl_Image *> * texture = 0;
4709     for (int i=2;i<styles;++i){
4710       gen & attr=style[i];
4711       if (attr.type==_VECT && attr._VECTptr->size()<=3 ){
4712 	gen attrv0=attr._VECTptr->front();
4713 	if (attrv0.type==_INT_ && attrv0.val==_GL_TEXTURE){
4714 	  gen attrv1=(*attr._VECTptr)[1];
4715 	  if (attrv1.type==_VECT && attrv1._VECTptr->size()==2 && attrv1._VECTptr->front().type==_STRNG && is_undef(attrv1._VECTptr->back())){
4716 	    // reload cached image
4717 	    attrv1=attrv1._VECTptr->front();
4718 	    std::map<std::string,std::pair<Fl_Image *,Fl_Image*> *>::iterator it,itend=texture2d_cache.end();
4719 	    it=texture2d_cache.find(attrv1._STRNGptr->c_str());
4720 	    if (it!=itend){
4721 	      std::pair<Fl_Image *,Fl_Image*> * old= it->second;
4722 	      delete old;
4723 	      texture2d_cache.erase(it);
4724 	    }
4725 	  }
4726 	  if (attrv1.type==_STRNG){
4727 	    get_texture2d(*attrv1._STRNGptr,texture);
4728 	  }
4729 	  // set texture
4730 	  continue;
4731 	} // end attrv0 = gl_texture
4732       }
4733     }
4734     if (s==at_pnt){
4735       // f[0]=complex pnt or vector of complex pnts or symbolic
4736       // f[1] -> style
4737       // f[2] optional=label
4738       gen point=f[0];
4739       if (point.type==_VECT && point.subtype==_POINT__VECT)
4740 	return;
4741       if ( (f[0].type==_SYMB) && (f[0]._SYMBptr->sommet==at_curve) && (f[0]._SYMBptr->feuille.type==_VECT) && (f[0]._SYMBptr->feuille._VECTptr->size()) ){
4742 	// Mon_image.show_mouse_on_object=false;
4743 	point=f[0]._SYMBptr->feuille._VECTptr->back();
4744 	if (type_line>=4 && point.type==_VECT && point._VECTptr->size()>2){
4745 	  vecteur v=*point._VECTptr;
4746 	  int vs=v.size()/2; // 3 -> 1
4747 	  if (Mon_image.findij(v[vs],x_scale,y_scale,i0,j0,contextptr) && Mon_image.findij(v[vs+1],x_scale,y_scale,i1,j1,contextptr)){
4748 	    bool logx=Mon_image.display_mode & 0x400,logy=Mon_image.display_mode & 0x800;
4749 	    checklog_fl_line(i0,j0,i1,j1,deltax,deltay,logx,logy,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
4750 	    double dx=i0-i1,dy=j0-j1;
4751 	    petite_fleche(i1,j1,dx,dy,deltax,deltay,width+3);
4752 	  }
4753 	}
4754       }
4755       if (is_undef(point))
4756 	return;
4757       if ( equalposcomp(Mon_image.selected,plot_i))
4758 	fl_color(FL_BLUE);
4759       else
4760 	xcas_color(couleur);
4761       fl_line_style(type_line,width+1,0);
4762       if (point.type==_SYMB) {
4763 	if (point._SYMBptr->sommet==at_hyperplan || point._SYMBptr->sommet==at_hypersphere)
4764 	  return;
4765 	/* fl_curve is a filled curved, not a Bezier curve!
4766 	if (point._SYMBptr->sommet==at_Bezier && point._SYMBptr->feuille.type==_VECT && point._SYMBptr->feuille._VECTptr->size()==4){
4767 	  vecteur v=*point._SYMBptr->feuille._VECTptr;
4768 	  double i2,j2,i3,j3; gen e,f0,f1;
4769 	  evalfdouble2reim(v[0],e,f0,f1,contextptr);
4770 	  i0=f0._DOUBLE_val; j0=f1._DOUBLE_val;
4771 	  evalfdouble2reim(v[1],e,f0,f1,contextptr);
4772 	  i1=f0._DOUBLE_val; j1=f1._DOUBLE_val;
4773 	  evalfdouble2reim(v[2],e,f0,f1,contextptr);
4774 	  i2=f0._DOUBLE_val; j2=f1._DOUBLE_val;
4775 	  evalfdouble2reim(v[3],e,f0,f1,contextptr);
4776 	  i3=f0._DOUBLE_val; j3=f1._DOUBLE_val;
4777 	  fl_push_matrix();
4778 	  fl_translate(deltax,deltay);
4779 	  fl_mult_matrix(x_scale,0,0,-y_scale,0,0);
4780 	  fl_translate(-Mon_image.window_xmin,-Mon_image.window_ymax);
4781 	  fl_curve(i0,j0,i1,j1,i2,j2,i3,j3);
4782 	  fl_end_complex_polygon();
4783 	  fl_pop_matrix(); // Restore initial matrix
4784 	  return;
4785 	}
4786 	*/
4787 	if (point._SYMBptr->sommet==at_cercle && !(Mon_image.display_mode & 0xc00)){
4788 	  vecteur v=*point._SYMBptr->feuille._VECTptr;
4789 	  gen diametre=remove_at_pnt(v[0]);
4790 	  gen e1=diametre._VECTptr->front().evalf_double(1,contextptr),e2=diametre._VECTptr->back().evalf_double(1,contextptr);
4791 	  gen centre=rdiv(e1+e2,2.0,contextptr);
4792 	  gen e12=e2-e1;
4793 	  double ex=evalf_double(re(e12,contextptr),1,contextptr)._DOUBLE_val,ey=evalf_double(im(e12,contextptr),1,contextptr)._DOUBLE_val;
4794 	  if (!Mon_image.findij(centre,x_scale,y_scale,i0,j0,contextptr))
4795 	    return;
4796 	  gen diam=std::sqrt(ex*ex+ey*ey);
4797 	  gen angle=std::atan2(ey,ex);
4798 	  gen a1=v[1].evalf_double(1,contextptr),a2=v[2].evalf_double(1,contextptr);
4799 	  if ( (diam.type==_DOUBLE_) && (a1.type==_DOUBLE_) && (a2.type==_DOUBLE_) ){
4800 	    i1=diam._DOUBLE_val*x_scale/2.0;
4801 	    j1=diam._DOUBLE_val*y_scale/2.0;
4802 	    double a1d=a1._DOUBLE_val,a2d=a2._DOUBLE_val,angled=angle._DOUBLE_val;
4803 	    bool changer_sens=a1d>a2d;
4804 	    if (changer_sens){
4805 	      double tmp=a1d;
4806 	      a1d=a2d;
4807 	      a2d=tmp;
4808 	    }
4809 	    double anglei=(angled+a1d),anglef=(angled+a2d),anglem=(anglei+anglef)/2;
4810 	    double diff=anglef-anglei;
4811 	    anglei -= floor(anglei/2/M_PI)*2*M_PI;
4812 	    anglef = anglei + diff;
4813 	    if (fill_polygon){
4814 	      if (v[1]==0 && v[2]==cst_two_pi)
4815 		fl_pie(deltax+round(i0-i1),deltay+round(j0-j1),round(2*i1),round(2*j1),0,360);
4816 	      else
4817 		fl_pie(deltax+round(i0-i1),deltay+round(j0-j1),round(2*i1),round(2*j1),anglei*180/M_PI,anglef*180/M_PI);
4818 	    }
4819 	    else {
4820 	      fl_arc(deltax+round(i0-i1),deltay+round(j0-j1),round(2*i1),round(2*j1),anglei*180/M_PI,anglef*180/M_PI);
4821 	      if (v.size()>=4){ // if cercle has the optionnal 5th arg
4822 		if (v[3]==2)
4823 		  petite_fleche(i0+i1*std::cos(anglem),j0-j1*std::sin(anglem),-i1*std::sin(anglem),-j1*std::cos(anglem),deltax,deltay,width);
4824 		else {
4825 		  if (changer_sens)
4826 		    petite_fleche(i0+i1*std::cos(anglei),j0-j1*std::sin(anglei),-i1*std::sin(anglei),-j1*std::cos(anglei),deltax,deltay,width);
4827 		  else
4828 		    petite_fleche(i0+i1*std::cos(anglef),j0-j1*std::sin(anglef),i1*std::sin(anglef),j1*std::cos(anglef),deltax,deltay,width);
4829 		}
4830 	      }
4831 	    }
4832 	    // Label a few degrees from the start angle,
4833 	    // FIXME should use labelpos
4834 	    double anglel=angled+a1d+0.3;
4835 	    if (v.size()>=4 && v[3]==2)
4836 	      anglel=angled+(0.45*a1d+0.55*a2d);
4837 	    i0=i0+i1*std::cos(anglel);
4838 	    j0=j0-j1*std::sin(anglel);
4839 	    if (!hidden_name)
4840 	      draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
4841 	    return;
4842 	  }
4843 	} // end circle
4844 	if (point._SYMBptr->sommet==at_pixon){
4845 	  // pixon (i,j,color)
4846 	  if (point._SYMBptr->feuille.type!=_VECT)
4847 	    return;
4848 	  vecteur &v=*point._SYMBptr->feuille._VECTptr;
4849 	  if (v.size()<3 || v[0].type!=_INT_ || v[1].type!=_INT_ || v[2].type!=_INT_)
4850 	    return;
4851 	  int delta_i=v[0].val,delta_j=v[1].val,psx=0,psy=0;
4852 	  if (v.size()>3 && v[3].type==_INT_){
4853 	    if (v[3].val>0) psy=v[3].val; else psx=-v[3].val;
4854 	  }
4855 	  psx=pixon_size*(psx+1);
4856 	  psy=pixon_size*(psy+1);
4857 	  xcas_color(v[2].val);
4858 	  delta_i *= pixon_size;
4859 	  delta_j *= pixon_size;
4860 	  if (delta_i>=0 && delta_i<mxw && delta_j>=0 && delta_j<myw){
4861 #if 1
4862 	    check_fl_rectf(deltax+delta_i,deltay+delta_j,psx,psy,clip_x,clip_y,clip_w,clip_h,0,0);
4863 #else
4864 	    for (int i=0;i<psx;++i)
4865 	      for (int j=0;j<psy;++j)
4866 		check_fl_point(deltax+delta_i+i,deltay+delta_j+j,clip_x,clip_y,clip_w,clip_h,0,0);
4867 #endif
4868 	  }
4869 	  return;
4870 	}
4871 	if (point._SYMBptr->sommet==at_bitmap){
4872 	  // bitmap(vector of int (1 per line)), 1st line, 1st col, [type]
4873 	  if (point._SYMBptr->feuille.type!=_VECT)
4874 	    return;
4875 	  vecteur &v=*point._SYMBptr->feuille._VECTptr;
4876 	  if (v.size()<3 || v[0].type!=_VECT || v[1].type!=_INT_ || v[2].type!=_INT_ )
4877 	    return;
4878 	  int delta_i=v[1].val,delta_j=v[2].val;
4879 	  double xmin=Mon_image.window_xmin,ymin=Mon_image.window_ymin,xmax=Mon_image.window_xmax,ymax=Mon_image.window_ymax;
4880 	  //gen psize=_Pictsize(0);
4881 	  int bitmap_w=Mon_image.w()-int(Mon_image.ylegende*(Mon_image.show_axes?Mon_image.labelsize():0)),
4882 	    bitmap_h=Mon_image.h()-(Mon_image.show_axes?((Mon_image.title.empty()?1:2)*Mon_image.labelsize()):0);
4883 	  if (v.size()>8){
4884 	    xmin=v[3]._DOUBLE_val;
4885 	    xmax=v[4]._DOUBLE_val;
4886 	    ymin=v[5]._DOUBLE_val;
4887 	    ymax=v[6]._DOUBLE_val;
4888 	    bitmap_w=v[7].val;
4889 	    bitmap_h=v[8].val;
4890 	  }
4891 	  double bitmap_scalex=(xmax-xmin)/bitmap_w,scalex=(Mon_image.window_xmax-Mon_image.window_xmin)/(Mon_image.w()-int(Mon_image.ylegende*(Mon_image.show_axes?Mon_image.labelsize():0)));
4892 	  double bitmap_scaley=(ymax-ymin)/bitmap_h,scaley=(Mon_image.window_ymax-Mon_image.window_ymin)/(Mon_image.h()-(Mon_image.show_axes?((Mon_image.title.empty()?1:2)*Mon_image.labelsize()):0));
4893 	  double X,Y;
4894 	  int ii,jj;
4895 	  const_iterateur it=v[0]._VECTptr->begin(),itend=v[0]._VECTptr->end();
4896 	  for (;it!=itend;++it,++delta_i){
4897 	    if (it->type!=_INT_ && it->type!=_ZINT)
4898 	      continue;
4899 	    gen z=*it;
4900 	    mpz_t zz,zr;
4901 	    if (it->type==_INT_)
4902 	      mpz_init_set_ui(zz,it->val);
4903 	    else
4904 	      mpz_init_set(zz,*it->_ZINTptr);
4905 	    mpz_init(zr);
4906 	    for (int j=delta_j;mpz_sgn(zz);++j){
4907 	      mpz_tdiv_r_2exp (zr, zz, 1);
4908 	      mpz_tdiv_q_2exp (zz, zz, 1);
4909 	      if (mpz_sgn(zr)){
4910 		X=xmin+j*bitmap_scalex;
4911 		ii=int(0.5+(X-Mon_image.window_xmin)/scalex);
4912 		Y=ymax-delta_i*bitmap_scaley;
4913 		jj=int(0.5+(Mon_image.window_ymax-Y)/scaley);
4914 		if (ii>0 && ii<mxw && jj>0 && jj<myw)
4915 		  check_fl_point(deltax+ii,deltay+jj,clip_x,clip_y,clip_w,clip_h,0,0);
4916 	      }
4917 	    }
4918 	    mpz_clear(zr);
4919 	    mpz_clear(zz);
4920 	  }
4921 	  return;
4922 	} // end bitmap
4923 	if (point._SYMBptr->sommet==at_legende){
4924 	  gen & f=point._SYMBptr->feuille;
4925 	  if (f.type==_VECT && f._VECTptr->size()==3){
4926 	    vecteur & fv=*f._VECTptr;
4927 	    if (fv[0].type==_VECT && fv[0]._VECTptr->size()>=2 && fv[1].type==_STRNG && fv[2].type==_INT_){
4928 	      vecteur & fvv=*fv[0]._VECTptr;
4929 	      if (fvv[0].type==_INT_ && fvv[1].type==_INT_){
4930 		fl_font(FL_HELVETICA,Mon_image.labelsize());
4931 		xcas_color(fv[2].val);
4932 		int dx=0,dy=0;
4933 		string legendes(*fv[1]._STRNGptr);
4934 		find_dxdy(legendes,labelpos,Mon_image.labelsize(),dx,dy);
4935 		fl_draw(legendes.c_str(),deltax+fvv[0].val+dx,deltay+fvv[1].val+dy);
4936 	      }
4937 	    }
4938 	  }
4939 	}
4940       } // end point.type==_SYMB
4941       if (point.type!=_VECT || (point.type==_VECT && (point.subtype==_GROUP__VECT || point.subtype==_VECTOR__VECT) && point._VECTptr->size()==2 && is_zero(point._VECTptr->back()-point._VECTptr->front())) ){ // single point
4942 	if (!Mon_image.findij((point.type==_VECT?point._VECTptr->front():point),x_scale,y_scale,i0,j0,contextptr))
4943 	  return;
4944 	if (i0>0 && i0<mxw && j0>0 && j0<myw)
4945 	  fltk_point(deltax,deltay,round(i0),round(j0),epaisseur_point,type_point);
4946 	if (!hidden_name)
4947 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
4948 	return;
4949       }
4950       // path
4951       const_iterateur jt=point._VECTptr->begin(),jtend=point._VECTptr->end();
4952       if (jt==jtend)
4953 	return;
4954       bool logx=Mon_image.display_mode & 0x400,logy=Mon_image.display_mode & 0x800;
4955       if (jtend-jt==2 && logx && point.subtype==_LINE__VECT){
4956 	// find points with + coordinates ax+cx*t=x, ay+cy*t=y=
4957 	gen a=*jt,ax=re(a,contextptr),ay=im(a,contextptr),b=*(jt+1),c=b-a,cx=re(c,contextptr),cy=im(c,contextptr);
4958 	if (!is_zero(cx)){
4959 	  // y=ay+cy/cx*(x-ax)
4960 	  gen x=pow(10,Mon_image.window_xmin,contextptr);
4961 	  gen y=ay+cy/cx*(x-ax);
4962 	  Mon_image.findij(x+cst_i*y,x_scale,y_scale,i0,j0,contextptr);
4963 	  for (int i=1;i<=logplot_points;++i){
4964 	    x=pow(10,Mon_image.window_xmin+i*(Mon_image.window_xmax-Mon_image.window_xmin)/logplot_points,contextptr);
4965 	    y=ay+cy/cx*(x-ax);
4966 	    Mon_image.findij(x+cst_i*y,x_scale,y_scale,i1,j1,contextptr);
4967 	    fl_line(round(i0+deltax),round(j0+deltay),round(i1+deltax),round(j1+deltay));
4968 	    i0=i1;
4969 	    j0=j1;
4970 	  }
4971 	  return;
4972 	}
4973       }
4974       if (texture && jtend-jt>2){
4975 	// use *jt and *(jt+2) for the rectangle texture
4976 	Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr);
4977 	if (!Mon_image.findij(*(jt+2),x_scale,y_scale,i1,j1,contextptr))
4978 	  return;
4979 	if (i0>i1)
4980 	  std::swap(i0,i1);
4981 	if (j0>j1)
4982 	  std::swap(j0,j1);
4983 	int tx=int(i0+.5)+deltax;
4984 	int tw=int(i1-i0+.5);
4985 	int ty=int(j0+.5)+deltay;
4986 	int th=int(j1-j0+.5);
4987 	if (texture->second && texture->second->w()==tw && texture->second->h()==th)
4988 	  texture->second->draw(tx,ty,tw,th);
4989 	else {
4990 	  if (texture->second)
4991 	    delete texture->second;
4992 	  if (texture->first){
4993 	    texture->second=texture->first->copy(tw,th);
4994 	    texture->second->draw(tx,ty,tw,th);
4995 	  }
4996 	}
4997 	return;
4998       }
4999       if (jt->type==_VECT)
5000 	return;
5001       if ( (type_point || epaisseur_point>2) && type_line==0 && width==0){
5002 	for (;jt!=jtend;++jt){
5003 	  if (!Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr))
5004 	    return;
5005 	  if (i0>0 && i0<mxw && j0>0 && j0<myw)
5006 	    fltk_point(deltax,deltay,round(i0),round(j0),epaisseur_point,type_point);
5007 	}
5008 	if (!hidden_name)
5009 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
5010 	return;
5011       }
5012       // initial point
5013       if (!Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr))
5014 	return;
5015       if (fill_polygon){
5016 	const_iterateur jtsave=jt;
5017 	gen e,f0,f1;
5018 	// Compute matrix for complex drawing
5019 	fl_push_matrix();
5020 	fl_translate(deltax,deltay);
5021 	fl_mult_matrix(x_scale,0,0,-y_scale,0,0);
5022 	fl_translate(-Mon_image.window_xmin,-Mon_image.window_ymax);
5023 	fl_begin_complex_polygon();
5024 	for (;jt!=jtend;++jt){
5025 	  evalfdouble2reim(*jt,e,f0,f1,contextptr);
5026 	  if ((f0.type==_DOUBLE_) && (f1.type==_DOUBLE_))
5027 	    fl_vertex(f0._DOUBLE_val,f1._DOUBLE_val);
5028 	}
5029 	if (*jtsave!=*(jtend-1)){
5030 	  evalfdouble2reim(*jtsave,e,f0,f1,contextptr);
5031 	  if ((f0.type==_DOUBLE_) && (f1.type==_DOUBLE_))
5032 	    fl_vertex(f0._DOUBLE_val,f1._DOUBLE_val);
5033 	}
5034 	fl_end_complex_polygon();
5035 	fl_pop_matrix(); // Restore initial matrix
5036 	if (!width){
5037 	  if (!hidden_name)
5038 	    draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
5039 	  return;
5040 	}
5041 	jt=jtsave;
5042 	fl_line_style(type_line,width,0);
5043 	fl_color(epaisseur_point-2+(type_point<<3));
5044       }
5045       i0save=i0;
5046       j0save=j0;
5047       ++jt;
5048       if (jt==jtend){
5049 	if (i0>0 && i0<mxw && j0>0 && j0<myw)
5050 	  check_fl_point(deltax+round(i0),deltay+round(j0),clip_x,clip_y,clip_w,clip_h,0,0);
5051 	if (!hidden_name)
5052 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
5053 	return;
5054       }
5055       bool seghalfline=( point.subtype==_LINE__VECT || point.subtype==_HALFLINE__VECT ) && (point._VECTptr->size()==2);
5056       // rest of the path
5057       for (;;){
5058 	if (!Mon_image.findij(*jt,x_scale,y_scale,i1,j1,contextptr))
5059 	  return;
5060 	if (!seghalfline){
5061 	  checklog_fl_line(i0,j0,i1,j1,deltax,deltay,logx,logy,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
5062 	  if (point.subtype==_VECTOR__VECT){
5063 	    double dx=i0-i1,dy=j0-j1;
5064 	    petite_fleche(i1,j1,dx,dy,deltax,deltay,width);
5065 	  }
5066 	}
5067 	++jt;
5068 	if (jt==jtend){ // label of line at midpoint
5069 	  if (point.subtype==_LINE__VECT){
5070 	    i0=(6*i1-i0)/5-8;
5071 	    j0=(6*j1-j0)/5-8;
5072 	  }
5073 	  else {
5074 	    i0=(i0+i1)/2-8;
5075 	    j0=(j0+j1)/2;
5076 	  }
5077 	  break;
5078 	}
5079 	i0=i1;
5080 	j0=j1;
5081       }
5082       // check for a segment/halfline/line
5083       if ( seghalfline){
5084 	double deltai=i1-i0save,adeltai=std::abs(deltai);
5085 	double deltaj=j1-j0save,adeltaj=std::abs(deltaj);
5086 	if (point.subtype==_LINE__VECT){
5087 	  if (deltai==0)
5088 	    checklog_fl_line(i1,0,i1,clip_h,deltax,deltay,logx,logy,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
5089 	  else {
5090 	    if (deltaj==0)
5091 	      checklog_fl_line(0,j1,clip_w,j1,deltax,deltay,Mon_image.display_mode & 0x400,Mon_image.display_mode & 0x800,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
5092 	    else {
5093 	      // Find the intersections with the 4 rectangle segments
5094 	      // Horizontal x=0 or w =i1+t*deltai: y=j1+t*deltaj
5095 	      vector< complex<double> > pts;
5096 	      double y0=j1-i1/deltai*deltaj,tol=clip_h*1e-6;
5097 	      if (y0>=-tol && y0<=clip_h+tol)
5098 		pts.push_back(complex<double>(0.0,y0));
5099 	      double yw=j1+(clip_w-i1)/deltai*deltaj;
5100 	      if (yw>=-tol && yw<=clip_h+tol)
5101 		pts.push_back(complex<double>(clip_w,yw));
5102 	      // Vertical y=0 or h=j1+t*deltaj, x=i1+t*deltai
5103 	      double x0=i1-j1/deltaj*deltai;
5104 	      tol=clip_w*1e-6;
5105 	      if (x0>=-tol && x0<=clip_w+tol)
5106 		pts.push_back(complex<double>(x0,0.0));
5107 	      double xh=i1+(clip_h-j1)/deltaj*deltai;
5108 	      if (xh>=-tol && xh<=clip_w+tol)
5109 		pts.push_back(complex<double>(xh,clip_h));
5110 	      if (pts.size()>=2)
5111 		checklog_fl_line(pts[0].real(),pts[0].imag(),pts[1].real(),pts[1].imag(),deltax,deltay,Mon_image.display_mode & 0x400,Mon_image.display_mode & 0x800,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
5112 	    } // end else adeltai==0 , adeltaj==0
5113 	  } // end else adeltai==0
5114 	} // end LINE_VECT
5115 	else {
5116 	  double N=1;
5117 	  if (adeltai){
5118 	    N=clip_w/adeltai+1;
5119 	    if (adeltaj)
5120 	      N=max(N,clip_h/adeltaj+1);
5121 	  }
5122 	  else {
5123 	    if (adeltaj)
5124 	      N=clip_h/adeltaj+1;
5125 	  }
5126 	  N *= 2; // increase N since rounding might introduce too small clipping
5127 	  while (fabs(N*deltai)>10000)
5128 	    N /= 2;
5129 	  while (fabs(N*deltaj)>10000)
5130 	    N /= 2;
5131 	  checklog_fl_line(i0save,j0save,i1+N*deltai,j1+N*deltaj,deltax,deltay,Mon_image.display_mode & 0x400,Mon_image.display_mode & 0x800,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale);
5132 	}
5133       } // end seghalfline
5134       if ( (point.subtype==_GROUP__VECT) && (point._VECTptr->size()==2))
5135 	; // no legend for segment
5136       else {
5137 	if (!hidden_name)
5138 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0);
5139       }
5140     } // end pnt subcase
5141 
5142   }
5143 
draw()5144   void Mouse_Position::draw(){
5145     int clip_x,clip_y,clip_w,clip_h;
5146     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
5147     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
5148     fl_color(FL_CYAN);
5149     check_fl_rectf(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h,0,0);
5150     fl_color(FL_BLACK);
5151     check_fl_rect(x(), y(), w(), h(),clip_x,clip_y,clip_w,clip_h,0,0);
5152     fl_font(FL_HELVETICA,labelsize());
5153     int cur_x,cur_y;
5154     // giac::context * contextptr = get_context(graphic);
5155     if (Graph2d * gr=dynamic_cast<Graph2d *>(graphic)){
5156       cur_x=gr->current_i; // Fl::event_x()-gr->x();
5157       cur_y=gr->current_j; // Fl::event_y()-gr->y();
5158       double y_scale=(gr->h()-(gr->show_axes?((gr->title.empty()?1:2)*gr->labelsize()):0))/(graphic->window_ymax-graphic->window_ymin);
5159       double x_scale=(gr->w()-(gr->show_axes?gr->ylegende*gr->labelsize():0))/(graphic->window_xmax-graphic->window_xmin);
5160       double d_mouse_x=graphic->window_xmin+cur_x/x_scale;
5161       double d_mouse_y=graphic->window_ymax-cur_y/y_scale;
5162       check_fl_draw(("x:"+giac::print_DOUBLE_(d_mouse_x,3)).c_str(),x()+2,y()+h()/2-2,clip_x,clip_y,clip_w,clip_h,0,0);
5163       check_fl_draw(("y:"+giac::print_DOUBLE_(d_mouse_y,3)).c_str(),x()+2,y()+h()-2,clip_x,clip_y,clip_w,clip_h,0,0);
5164     }
5165     if (Graph3d * gr=dynamic_cast<Graph3d *>(graphic)){
5166       cur_x=gr->current_i; // Fl::event_x();
5167       cur_y=gr->current_j; // Fl::event_y();
5168       double x0,y0,z0;
5169       gr->find_xyz(cur_x,cur_y,gr->depth,x0,y0,z0);
5170       fl_draw(("x:"+giac::print_DOUBLE_(x0,3)).c_str(),x()+2,y()+labelsize()-2);
5171       fl_draw(("y:"+giac::print_DOUBLE_(y0,3)).c_str(),x()+2,y()+2*labelsize()-2);
5172       fl_draw(("z:"+giac::print_DOUBLE_(z0,3)).c_str(),x()+2,y()+3*labelsize()-2);
5173     }
5174     fl_pop_clip();
5175   }
5176 
printstring(const gen & g,GIAC_CONTEXT)5177   string printstring(const gen & g,GIAC_CONTEXT){
5178     if (g.type==_STRNG)
5179       return *g._STRNGptr;
5180     return g.print(contextptr);
5181   }
5182 
find_title_plot(gen & title_tmp,gen & plot_tmp,GIAC_CONTEXT)5183   void Graph2d3d::find_title_plot(gen & title_tmp,gen & plot_tmp,GIAC_CONTEXT){
5184     if (in_area && mode && !args_tmp.empty()){
5185       if (args_tmp.size()>=2){
5186 	gen function=(mode==int(args_tmp.size()))?function_final:function_tmp;
5187 	if (function.type==_FUNC){
5188 	  bool dim2=dynamic_cast<Graph2d *>(this);
5189 	  vecteur args2=args_tmp;
5190 	  if ( *function._FUNCptr==(dim2?at_cercle:at_sphere)){
5191 	    gen argv1;
5192 	    try {
5193 	      argv1=evalf(args_tmp.back(),1,contextptr);
5194 	      argv1=evalf_double(argv1,1,contextptr);
5195 	    }
5196 	    catch (std::runtime_error & e){
5197 	      argv1=undef;
5198 	    }
5199 	    if (argv1.is_symb_of_sommet(at_pnt) ||argv1.type==_IDNT){
5200 	      argv1=remove_at_pnt(argv1);
5201 	      if ( (argv1.type==_VECT && argv1.subtype==_POINT__VECT) || argv1.type==_CPLX || argv1.type==_IDNT)
5202 		args2.back()=args_tmp.back()-args_tmp.front();
5203 	    }
5204 	  }
5205 	  if (function==at_ellipse)
5206 	    ;
5207 	  title_tmp=gen(args2,_SEQ__VECT);
5208 	  bool b=approx_mode(contextptr);
5209 	  if (!b)
5210 	    approx_mode(true,contextptr);
5211 	  plot_tmp=symbolic(*function._FUNCptr,title_tmp);
5212 	  if (!lidnt(title_tmp).empty())
5213 	    ; // cerr << plot_tmp << '\n';
5214 	  bool bb=io_graph(contextptr);
5215 	  int locked=0;
5216 	  if (bb){
5217 #ifdef HAVE_LIBPTHREAD
5218 	    // cerr << "plot title lock" << '\n';
5219 	    locked=pthread_mutex_trylock(&interactive_mutex);
5220 #endif
5221 	    if (!locked)
5222 	      io_graph(false,contextptr);
5223 	  }
5224 	  plot_tmp=protecteval(plot_tmp,1,contextptr);
5225 	  if (bb && !locked){
5226 	    io_graph(bb,contextptr);
5227 #ifdef HAVE_LIBPTHREAD
5228 	    pthread_mutex_unlock(&interactive_mutex);
5229 	    // cerr << "plot title unlock" << '\n';
5230 #endif
5231 	  }
5232 	  if (!b)
5233 	    approx_mode(false,contextptr);
5234 	} // end function.type==_FUNC
5235 	else
5236 	  title_tmp=gen(args_tmp,_SEQ__VECT);
5237       } // end size()>=2
5238       else
5239 	title_tmp=args_tmp;
5240     }
5241   }
5242 
in_draw(int clip_x,int clip_y,int clip_w,int clip_h,int & vertical_pixels)5243   void Graph2d::in_draw(int clip_x,int clip_y,int clip_w,int clip_h,int & vertical_pixels){
5244     if (window_xmax-window_xmin<1e-100){
5245       window_xmax=gnuplot_xmax;
5246       window_xmin=gnuplot_xmin;
5247     }
5248     if (window_ymax-window_ymin<1e-100){
5249       window_ymax=gnuplot_ymax;
5250       window_ymin=gnuplot_ymin;
5251     }
5252     struct timezone tz;
5253     gettimeofday(&animation_last,&tz);
5254     gen title_tmp;
5255     gen plot_tmp;
5256     History_Pack * hp =get_history_pack(this);
5257     context * contextptr=hp?hp->contextptr:get_context(this);
5258     find_title_plot(title_tmp,plot_tmp,contextptr);
5259 #if 1 // changes by L. Marohnic
5260     int horizontal_pixels=w()-(show_axes>0?int(ylegende*labelsize())+2:0);
5261     vertical_pixels=h()-((show_axes!=0 && show_axes!=2?2:0)+(!title.empty()))*labelsize();
5262     int deltax=x(),deltay=y();
5263     double y_scale=vertical_pixels/(window_ymax-window_ymin);
5264     double x_scale=horizontal_pixels/(window_xmax-window_xmin);
5265     // Then redraw the background
5266     fl_color(FL_WHITE);
5267     fl_rectf(clip_x, clip_y, clip_w, clip_h);
5268     if (background_image){
5269       if (!background_image->second || background_image->second->w()!=w() || background_image->second->h()!=h()){
5270 	if (background_image->second)
5271 	  delete background_image->second;
5272 	if (background_image->first)
5273 	  background_image->second=background_image->first->copy(w(),h());
5274       }
5275       if (background_image->second)
5276 	background_image->second->draw(x(),y(),w(),h());
5277     }
5278     // History draw
5279     /****************/
5280     int xx,yy,ww,hh;
5281     fl_clip_box(clip_x,clip_y,horizontal_pixels,vertical_pixels,xx,yy,ww,hh);
5282     fl_push_clip(xx,yy,ww,hh);
5283     // fl_push_clip(clip_x,clip_y,horizontal_pixels,vertical_pixels);
5284     /****************/
5285     fl_color(FL_BLACK);
5286     fl_font(FL_HELVETICA,labelsize());
5287     if ( (display_mode & 2) && !animation_instructions.empty()){
5288       gen tmp=animation_instructions[animation_instructions_pos % animation_instructions.size()];
5289       fltk_draw(*this,-1,tmp,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5290     }
5291     if ( display_mode & 0x40 ){
5292       fltk_draw(*this,-1,trace_instructions,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5293     }
5294     if (display_mode & 1) {
5295       const_iterateur at=plot_instructions.begin(),atend=plot_instructions.end(),it,itend;
5296       for (int plot_i=0;at!=atend;++at,++plot_i){
5297 	if (at->type==_INT_)
5298 	  continue;
5299 	update_infos(*at,contextptr);
5300 	if (at->is_symb_of_sommet(at_parameter)){
5301 	  gen ff = at->_SYMBptr->feuille;
5302 	  vecteur f;
5303 	  if (ff.type==_VECT && (f=*ff._VECTptr).size()==4){
5304 	    // parameters.push_back(f);
5305 	  }
5306 	  continue;
5307 	}
5308 	fltk_draw(*this,plot_i,*at,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5309       } // end for at
5310     }
5311     vecteur plot_tmp_v=gen2vecteur(plot_tmp);
5312     const_iterateur jt=plot_tmp_v.begin(),jtend=plot_tmp_v.end();
5313     for (;jt!=jtend;++jt){
5314       gen plot_tmp=*jt;
5315       if (plot_tmp.is_symb_of_sommet(at_pnt) && plot_tmp._SYMBptr->feuille.type==_VECT && !plot_tmp._SYMBptr->feuille._VECTptr->empty()){
5316 	vecteur & v=*plot_tmp._SYMBptr->feuille._VECTptr;
5317 	// cerr << v << '\n';
5318 	if (v[1].type==_INT_)
5319 	  plot_tmp=symbolic(at_pnt,makevecteur(v[0],v[1].val | _DOT_LINE | _LINE_WIDTH_2));
5320 	else
5321 	  plot_tmp=symbolic(at_pnt,v);
5322 	try {
5323 	  fltk_draw(*this,-1,plot_tmp,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5324 	}
5325 	catch (...){
5326 	}
5327       }
5328     }
5329     fl_line_style(0); // back to default line style
5330     // Draw axis
5331     double I0,J0;
5332     findij(zero,x_scale,y_scale,I0,J0,contextptr);
5333     int i_0=round(I0),j_0=round(J0);
5334     if ( show_axes==1 &&  (window_ymax>=0) && (window_ymin<=0)){ // X-axis
5335       fl_color(x_axis_color);
5336       check_fl_line(deltax,deltay+j_0,deltax+horizontal_pixels,deltay+j_0,clip_x,clip_y,clip_w,clip_h,0,0);
5337       fl_color(FL_CYAN);
5338       check_fl_line(deltax+i_0,deltay+j_0,deltax+i_0+int(x_scale),deltay+j_0,clip_x,clip_y,clip_w,clip_h,0,0);
5339       fl_color(x_axis_color);
5340       if (x_tick>0 && (horizontal_pixels)/(x_scale*x_tick) < 40){
5341 	double nticks=(horizontal_pixels-I0)/(x_scale*x_tick);
5342 	int count=0;
5343 	for (int ii=int(-I0/(x_tick*x_scale));ii<=nticks && count<40;++ii,++count){
5344 	  int iii=int(I0+ii*x_scale*x_tick+.5);
5345 	  check_fl_line(deltax+iii,deltay+j_0+2,deltax+iii,deltay+j_0-2,clip_x,clip_y,clip_w,clip_h,0,0);
5346 	}
5347       }
5348       string tmp=(x_axis_name.empty()?"x":x_axis_name)+" ";
5349       check_fl_draw(tmp.c_str(),deltax+horizontal_pixels-int(fl_width(tmp.c_str())),deltay+j_0+labelsize(),clip_x,clip_y,clip_w,clip_h,0,0);
5350     }
5351     if ( show_axes==1 && (window_xmax>=0) && (window_xmin<=0) ) {// Y-axis
5352       fl_color(y_axis_color);
5353       check_fl_line(deltax+i_0,deltay,deltax+i_0,deltay+vertical_pixels,clip_x,clip_y,clip_w,clip_h,0,0);
5354       fl_color(FL_CYAN);
5355       check_fl_line(deltax+i_0,deltay+j_0,deltax+i_0,deltay+j_0-int(y_scale),clip_x,clip_y,clip_w,clip_h,0,0);
5356       fl_color(y_axis_color);
5357       if (y_tick>0 && vertical_pixels/(y_tick*y_scale) <40 ){
5358 	double nticks=(vertical_pixels-J0)/(y_tick*y_scale);
5359 	int count=0;
5360 	for (int jj=int(-J0/(y_tick*y_scale));jj<=nticks && count<25;++jj,++count){
5361 	  int jjj=int(J0+jj*y_scale*y_tick+.5);
5362 	  check_fl_line(deltax+i_0-2,deltay+jjj,deltax+i_0+2,deltay+jjj,clip_x,clip_y,clip_w,clip_h,0,0);
5363 	}
5364       }
5365       string tmp=" "+(y_axis_name.empty()?"y":y_axis_name);
5366       check_fl_draw(tmp.c_str(),deltax+i_0+2,deltay+labelsize(),clip_x,clip_y,clip_w,clip_h,0,0);
5367     }
5368     // Ticks
5369     if (show_axes==1 && (horizontal_pixels)/(x_scale*x_tick) < 40 && vertical_pixels/(y_tick*y_scale) <40  ){
5370       if (x_tick>0 && y_tick>0 ){
5371   fl_color(FL_BLACK);
5372 	double nticks=(horizontal_pixels-I0)/(x_scale*x_tick);
5373 	double mticks=(vertical_pixels-J0)/(y_tick*y_scale);
5374 	int count=0;
5375 	for (int ii=int(-I0/(x_tick*x_scale));ii<=nticks;++ii){
5376 	  int iii=int(I0+ii*x_scale*x_tick+.5);
5377 	  for (int jj=int(-J0/(y_tick*y_scale));jj<=mticks && count<1600;++jj,++count){
5378 	    int jjj=int(J0+jj*y_scale*y_tick+.5);
5379 	    check_fl_point(deltax+iii,deltay+jjj,clip_x,clip_y,clip_w,clip_h,0,0);
5380 	  }
5381 	}
5382       }
5383     }
5384     /****************/
5385     fl_pop_clip();
5386     /****************/
5387     fl_color(FL_BLACK);
5388     fl_font(FL_HELVETICA,labelsize());
5389     if (!args_help.empty() && args_tmp.size()<= args_help.size()){
5390       fl_draw((gettext("Click ")+args_help[giacmax(1,args_tmp.size())-1]).c_str(),x(),y()+labelsize()-2);
5391     }
5392     string mytitle(title);
5393     if (!is_zero(title_tmp) && function_final.type==_FUNC)
5394       mytitle=gen(symbolic(*function_final._FUNCptr,title_tmp)).print(contextptr);
5395     if (!mytitle.empty()){
5396       int dt=int(fl_width(mytitle.c_str()));
5397       check_fl_draw(mytitle.c_str(),deltax+(horizontal_pixels-dt)/2,deltay+h()-labelsize()/4,clip_x,clip_y,clip_w,clip_h,0,0);
5398     }
5399     // Boundary values
5400     fl_font(FL_HELVETICA,labelsize());
5401     if (show_axes>=1){
5402       int taille,affs,delta;
5403       vecteur aff;
5404       string tmp;
5405       bool logx=display_mode & 0x400,logy=display_mode & 0x800;
5406       if (show_axes!=2) {
5407         // X
5408         //fl_color(x_axis_color);
5409         aff=ticks(window_xmin,window_xmax,true);
5410         affs=aff.size();
5411         double tickx,minx=DBL_MAX,maxx=DBL_MIN;
5412         for (int i=0;i<affs;++i){
5413     double d=evalf_double(aff[i],1,contextptr)._DOUBLE_val;
5414     tmp=print_DOUBLE_(logx?std::pow(10,d):d);
5415     delta=int(horizontal_pixels*(d-window_xmin)/(window_xmax-window_xmin));
5416     taille=int(fl_width(tmp.c_str()));
5417     if (delta>=taille/2 && delta<=horizontal_pixels){
5418       tickx=x()+delta;
5419       if (show_axes>1 || logx || d!=0)
5420         fl_line(tickx,y()+vertical_pixels-1,tickx,y()+vertical_pixels-5);
5421       if (minx>tickx) minx=tickx;
5422       if (maxx<tickx) maxx=tickx;
5423       if (args_tmp.empty()) {
5424         if  (show_axes==1) fl_color(x_axis_color);
5425         fl_draw(tmp.c_str(),tickx-taille/2,y()+vertical_pixels+labelsize());
5426         if (show_axes==1) fl_color(FL_BLACK);
5427       }
5428     }
5429         }
5430         if (args_tmp.empty())
5431     fl_draw(x_axis_unit.c_str(),x()+horizontal_pixels,y()+vertical_pixels+labelsize()-2);
5432         if (show_axes==3 && maxx!=DBL_MIN && minx!=DBL_MAX)
5433           fl_line(minx,y()+vertical_pixels,maxx,y()+vertical_pixels);
5434       }
5435       // Y
5436       //fl_color(y_axis_color);
5437       aff=ticks(window_ymin,window_ymax,true);
5438       affs=aff.size();
5439       taille=labelsize()/2;
5440       double ticky,miny=DBL_MAX,maxy=DBL_MIN;
5441       for (int j=0;j<affs;++j){
5442 	double d=evalf_double(aff[j],1,contextptr)._DOUBLE_val;
5443   if (show_axes>=2 && !logy && d<0)
5444     continue;
5445 	tmp=print_DOUBLE_(logy?std::pow(10,d):d)+y_axis_unit;
5446 	delta=int(vertical_pixels*(window_ymax-d)/(window_ymax-window_ymin));
5447 	if (delta>=taille && delta<=vertical_pixels-taille){
5448     ticky=y()+delta;
5449     if (show_axes>1 || logy || d!=0)
5450       fl_line(x()+horizontal_pixels-1,ticky,x()+horizontal_pixels-5,ticky);
5451     if (miny>ticky) miny=ticky;
5452     if (maxy<ticky) maxy=ticky;
5453     if (show_axes==1) fl_color(y_axis_color);
5454     fl_draw(tmp.c_str(),x()+horizontal_pixels+3,ticky+taille);
5455     if (show_axes==1) fl_color(FL_BLACK);
5456 	  int tmpi=fl_width(tmp.c_str());
5457 	  if (tmpi+horizontal_pixels+3>w()){
5458 	    ylegende=(tmpi+3.)/labelsize();
5459 	    redraw();
5460 	  }
5461 	}
5462       }
5463       if (show_axes>=2 && maxy!=DBL_MIN && miny!=DBL_MAX)
5464         fl_line(x()+horizontal_pixels,miny,x()+horizontal_pixels,maxy);
5465     }
5466     if (show_axes==1 || background_image) {
5467       fl_color(FL_BLACK);
5468       if ( !(display_mode & 0x100) )
5469         fl_rect(x(), y(), horizontal_pixels, vertical_pixels);
5470     }
5471 #else
5472     int horizontal_pixels=w()-(show_axes?int(ylegende*labelsize()):0);
5473     vertical_pixels=h()-((show_axes?1:0)+(!title.empty()))*labelsize();
5474     int deltax=x(),deltay=y();
5475     double y_scale=vertical_pixels/(window_ymax-window_ymin);
5476     double x_scale=horizontal_pixels/(window_xmax-window_xmin);
5477     // Then redraw the background
5478     fl_color(FL_WHITE);
5479     fl_rectf(clip_x, clip_y, clip_w, clip_h);
5480     fl_color(FL_BLACK);
5481     if ( !(display_mode & 0x100) )
5482       fl_rect(x(), y(), horizontal_pixels, vertical_pixels);
5483     if (background_image){
5484       if (!background_image->second || background_image->second->w()!=w() || background_image->second->h()!=h()){
5485 	if (background_image->second)
5486 	  delete background_image->second;
5487 	if (background_image->first)
5488 	  background_image->second=background_image->first->copy(w(),h());
5489       }
5490       if (background_image->second)
5491 	background_image->second->draw(x(),y(),w(),h());
5492     }
5493     // History draw
5494     /****************/
5495     int xx,yy,ww,hh;
5496     fl_clip_box(clip_x,clip_y,horizontal_pixels,vertical_pixels,xx,yy,ww,hh);
5497     fl_push_clip(xx,yy,ww,hh);
5498     // fl_push_clip(clip_x,clip_y,horizontal_pixels,vertical_pixels);
5499     /****************/
5500     fl_color(FL_BLACK);
5501     fl_font(FL_HELVETICA,labelsize());
5502     if ( (display_mode & 2) && !animation_instructions.empty()){
5503       gen tmp=animation_instructions[animation_instructions_pos % animation_instructions.size()];
5504       fltk_draw(*this,-1,tmp,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5505     }
5506     if ( display_mode & 0x40 ){
5507       fltk_draw(*this,-1,trace_instructions,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5508     }
5509     if (display_mode & 1) {
5510       const_iterateur at=plot_instructions.begin(),atend=plot_instructions.end(),it,itend;
5511       for (int plot_i=0;at!=atend;++at,++plot_i){
5512 	if (at->type==_INT_)
5513 	  continue;
5514 	update_infos(*at,contextptr);
5515 	if (at->is_symb_of_sommet(at_parameter)){
5516 	  gen ff = at->_SYMBptr->feuille;
5517 	  vecteur f;
5518 	  if (ff.type==_VECT && (f=*ff._VECTptr).size()==4){
5519 	    // parameters.push_back(f);
5520 	  }
5521 	  continue;
5522 	}
5523 	fltk_draw(*this,plot_i,*at,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5524       } // end for at
5525     }
5526     vecteur plot_tmp_v=gen2vecteur(plot_tmp);
5527     const_iterateur jt=plot_tmp_v.begin(),jtend=plot_tmp_v.end();
5528     for (;jt!=jtend;++jt){
5529       gen plot_tmp=*jt;
5530       if (plot_tmp.is_symb_of_sommet(at_pnt) && plot_tmp._SYMBptr->feuille.type==_VECT && !plot_tmp._SYMBptr->feuille._VECTptr->empty()){
5531 	vecteur & v=*plot_tmp._SYMBptr->feuille._VECTptr;
5532 	// cerr << v << '\n';
5533 	if (v[1].type==_INT_)
5534 	  plot_tmp=symbolic(at_pnt,makevecteur(v[0],v[1].val | _DOT_LINE | _LINE_WIDTH_2));
5535 	else
5536 	  plot_tmp=symbolic(at_pnt,v);
5537 	try {
5538 	  fltk_draw(*this,-1,plot_tmp,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h);
5539 	}
5540 	catch (...){
5541 	}
5542       }
5543     }
5544     fl_line_style(0); // back to default line style
5545     // Draw axis
5546     double I0,J0;
5547     findij(zero,x_scale,y_scale,I0,J0,contextptr);
5548     int i_0=round(I0),j_0=round(J0);
5549     if ( show_axes &&  (window_ymax>=0) && (window_ymin<=0)){ // X-axis
5550       fl_color(x_axis_color);
5551       check_fl_line(deltax,deltay+j_0,deltax+horizontal_pixels,deltay+j_0,clip_x,clip_y,clip_w,clip_h,0,0);
5552       fl_color(FL_CYAN);
5553       check_fl_line(deltax+i_0,deltay+j_0,deltax+i_0+int(x_scale),deltay+j_0,clip_x,clip_y,clip_w,clip_h,0,0);
5554       fl_color(x_axis_color);
5555       if (x_tick>0 && (horizontal_pixels)/(x_scale*x_tick) < 40){
5556 	double nticks=(horizontal_pixels-I0)/(x_scale*x_tick);
5557 	int count=0;
5558 	for (int ii=int(-I0/(x_tick*x_scale));ii<=nticks && count<40;++ii,++count){
5559 	  int iii=int(I0+ii*x_scale*x_tick+.5);
5560 	  check_fl_line(deltax+iii,deltay+j_0,deltax+iii,deltay+j_0-4,clip_x,clip_y,clip_w,clip_h,0,0);
5561 	}
5562       }
5563       string tmp=x_axis_name.empty()?"x":x_axis_name;
5564       check_fl_draw(tmp.c_str(),deltax+horizontal_pixels-int(fl_width(tmp.c_str())),deltay+j_0+labelsize(),clip_x,clip_y,clip_w,clip_h,0,0);
5565     }
5566     if ( show_axes && (window_xmax>=0) && (window_xmin<=0) ) {// Y-axis
5567       fl_color(y_axis_color);
5568       check_fl_line(deltax+i_0,deltay,deltax+i_0,deltay+vertical_pixels,clip_x,clip_y,clip_w,clip_h,0,0);
5569       fl_color(FL_CYAN);
5570       check_fl_line(deltax+i_0,deltay+j_0,deltax+i_0,deltay+j_0-int(y_scale),clip_x,clip_y,clip_w,clip_h,0,0);
5571       fl_color(y_axis_color);
5572       if (y_tick>0 && vertical_pixels/(y_tick*y_scale) <40 ){
5573 	double nticks=(vertical_pixels-J0)/(y_tick*y_scale);
5574 	int count=0;
5575 	for (int jj=int(-J0/(y_tick*y_scale));jj<=nticks && count<25;++jj,++count){
5576 	  int jjj=int(J0+jj*y_scale*y_tick+.5);
5577 	  check_fl_line(deltax+i_0,deltay+jjj,deltax+i_0+4,deltay+jjj,clip_x,clip_y,clip_w,clip_h,0,0);
5578 	}
5579       }
5580       check_fl_draw(y_axis_name.empty()?"y":y_axis_name.c_str(),deltax+i_0+2,deltay+labelsize(),clip_x,clip_y,clip_w,clip_h,0,0);
5581     }
5582     // Ticks
5583     if (show_axes && (horizontal_pixels)/(x_scale*x_tick) < 40 && vertical_pixels/(y_tick*y_scale) <40  ){
5584       if (x_tick>0 && y_tick>0 ){
5585 	fl_color(FL_BLACK);
5586 	double nticks=(horizontal_pixels-I0)/(x_scale*x_tick);
5587 	double mticks=(vertical_pixels-J0)/(y_tick*y_scale);
5588 	int count=0;
5589 	for (int ii=int(-I0/(x_tick*x_scale));ii<=nticks;++ii){
5590 	  int iii=int(I0+ii*x_scale*x_tick+.5);
5591 	  for (int jj=int(-J0/(y_tick*y_scale));jj<=mticks && count<1600;++jj,++count){
5592 	    int jjj=int(J0+jj*y_scale*y_tick+.5);
5593 	    check_fl_point(deltax+iii,deltay+jjj,clip_x,clip_y,clip_w,clip_h,0,0);
5594 	  }
5595 	}
5596       }
5597     }
5598     /****************/
5599     fl_pop_clip();
5600     /****************/
5601     fl_color(FL_BLACK);
5602     fl_font(FL_HELVETICA,labelsize());
5603     if (!args_help.empty() && args_tmp.size()<= args_help.size()){
5604       fl_draw((gettext("Click ")+args_help[giacmax(1,args_tmp.size())-1]).c_str(),x(),y()+labelsize()-2);
5605     }
5606     string mytitle(title);
5607     if (!is_zero(title_tmp) && function_final.type==_FUNC)
5608       mytitle=gen(symbolic(*function_final._FUNCptr,title_tmp)).print(contextptr);
5609     if (!mytitle.empty()){
5610       int dt=int(fl_width(mytitle.c_str()));
5611       check_fl_draw(mytitle.c_str(),deltax+(horizontal_pixels-dt)/2,deltay+h()-labelsize()/4,clip_x,clip_y,clip_w,clip_h,0,0);
5612     }
5613     // Boundary values
5614     fl_font(FL_HELVETICA,labelsize());
5615     if (show_axes){
5616       int taille,affs,delta;
5617       vecteur aff;
5618       string tmp;
5619       bool logx=display_mode & 0x400,logy=display_mode & 0x800;
5620       // X
5621       fl_color(x_axis_color);
5622       aff=ticks(window_xmin,window_xmax,true);
5623       affs=aff.size();
5624       for (int i=0;i<affs;++i){
5625 	double d=evalf_double(aff[i],1,contextptr)._DOUBLE_val;
5626 	tmp=print_DOUBLE_(logx?std::pow(10,d):d);
5627 	delta=int(horizontal_pixels*(d-window_xmin)/(window_xmax-window_xmin));
5628 	taille=int(fl_width(tmp.c_str()));
5629 	if (delta>=taille/2 && delta<=horizontal_pixels){
5630 	  fl_line(x()+delta,y()+vertical_pixels,x()+delta,y()+vertical_pixels+3);
5631 	  if (args_tmp.empty())
5632 	    fl_draw(tmp.c_str(),x()+delta-taille/2,y()+vertical_pixels+labelsize()-2);
5633 	}
5634       }
5635       if (args_tmp.empty())
5636 	fl_draw(x_axis_unit.c_str(),x()+horizontal_pixels,y()+vertical_pixels+labelsize()-2);
5637       // Y
5638       fl_color(y_axis_color);
5639       aff=ticks(window_ymin,window_ymax,true);
5640       affs=aff.size();
5641       taille=labelsize()/2;
5642       for (int j=0;j<affs;++j){
5643 	double d=evalf_double(aff[j],1,contextptr)._DOUBLE_val;
5644 	tmp=print_DOUBLE_(logy?std::pow(10,d):d)+y_axis_unit;
5645 	delta=int(vertical_pixels*(window_ymax-d)/(window_ymax-window_ymin));
5646 	if (delta>=taille && delta<=vertical_pixels-taille){
5647 	  fl_line(x()+horizontal_pixels,y()+delta,x()+horizontal_pixels+3,y()+delta);
5648 	  fl_draw(tmp.c_str(),x()+horizontal_pixels+3,y()+delta+taille);
5649 	  int tmpi=fl_width(tmp.c_str());
5650 	  if (tmpi+horizontal_pixels+3>w()){
5651 	    ylegende=(tmpi+3.)/labelsize();
5652 	    redraw();
5653 	  }
5654 	}
5655       }
5656     }
5657 #endif
5658   }
5659 
draw()5660   void Graph2d::draw(){
5661     int clip_x,clip_y,clip_w,clip_h;
5662     if (!hp)
5663       hp=geo_find_history_pack(this);
5664     context * contextptr = hp?hp->contextptr:0;
5665 #ifdef HAVE_LIBPTHREAD
5666     // cerr << "graph2d draw lock" << '\n';
5667     int locked=pthread_mutex_trylock(&interactive_mutex);
5668     if (locked)
5669       return;
5670 #endif
5671     bool b=io_graph(contextptr);
5672     io_graph(false,contextptr);
5673     bool block=block_signal;
5674     block_signal=true;
5675     // cerr << "graph2d draw " << this << " block_signal" << '\n';
5676     fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
5677     fl_push_clip(clip_x,clip_y,clip_w,clip_h);
5678     int horizontal_pixels=w()-(show_axes?int(ylegende*labelsize()):0);
5679     int vertical_pixels;
5680     int deltax=x(),deltay=y();
5681     in_draw(clip_x,clip_y,clip_w,clip_h,vertical_pixels);
5682     // Draw mouse drag
5683     if ( pushed && !waiting_click && current_i>=0 && current_i<=horizontal_pixels && current_j>=0 && current_j <=vertical_pixels && (push_i!=current_i || push_j!=current_j ) ){
5684       fl_color(FL_RED);
5685       check_fl_rect(deltax+min(push_i,current_i),deltay+min(push_j,current_j),absint(current_i-push_i),absint(current_j-push_j),clip_x,clip_y,clip_w,clip_h,0,0);
5686     }
5687     fl_pop_clip();
5688     if (!paused)
5689       ++animation_instructions_pos;
5690     // cerr << "graph2d draw " << this << " restore block_signal" << '\n';
5691     block_signal=block;
5692     io_graph(b,contextptr);
5693 #ifdef HAVE_LIBPTHREAD
5694     pthread_mutex_unlock(&interactive_mutex);
5695     // cerr << "graph2d draw unlock" << '\n';
5696 #endif
5697   }
5698 
autoname_plus_plus()5699   void Graph2d3d::autoname_plus_plus(){
5700     if (hp){
5701       string s=autoname(hp->contextptr);
5702       giac::autoname_plus_plus(s);
5703       autoname(s,hp->contextptr);
5704     }
5705   }
5706 
update(Fl_Group * pack,int pos)5707   void Graph2d3d::update(Fl_Group * pack,int pos){
5708     if (!pack)
5709       return;
5710     show();
5711     if (pos>=0){ // Check if we need to update from pos or pos+1
5712       if ( (last_event=FL_DRAG || last_event==FL_RELEASE) && pack->children()>pos){
5713 	Gen_Value_Slider * gs=dynamic_cast<Gen_Value_Slider *>(Fl::belowmouse());
5714 	if (gs){ // last handle required by a cursor?
5715 	  Fl_Widget * wid=pack->child(pos);
5716 	  Fl_Tile * t=dynamic_cast<Fl_Tile *>(wid);
5717 	  if (t && t->children()>=3)
5718 	    wid=t->child(2);
5719 	  Fl_Scroll * s =dynamic_cast<Fl_Scroll *>(wid);
5720 	  if (s)
5721 	    wid=s->child(0);
5722 	  if (const Gen_Output * go = dynamic_cast<const Gen_Output *>(wid)){
5723 	    if (go->value().is_symb_of_sommet(at_parameter))
5724 	      ++pos;
5725 	  }
5726 	  // cerr << clock() << " ++pos " << pos << " " << last_event << '\n';
5727 	}
5728 	else
5729 	  ; // cerr << clock() << " =pos " << pos << " " << last_event <<  '\n';
5730       }
5731     }
5732     else
5733       ++pos;
5734     // pack is normally a History_Pack
5735     clear(pos);
5736     add(pack,pos);
5737   }
5738 
add(const Fl_Widget * wid,int pos)5739   void Graph2d3d::add(const Fl_Widget * wid,int pos){
5740     if (const Gen_Output * g = dynamic_cast<const Gen_Output *>(wid)){
5741       add(g->value());
5742       return;
5743     }
5744     if (const Fl_Group * g = dynamic_cast<const Fl_Group *>(wid)){
5745       int n=g->children();
5746       for (int i=pos;i<n;++i){
5747 	const Fl_Widget * wid = g->child(i);
5748 	add(wid);
5749       }
5750     }
5751   }
5752 
clear(unsigned pos)5753   void Graph2d3d::clear(unsigned pos){
5754     redraw();
5755     // Clear plot_instructions starting at pos+1,
5756     // clear parameters starting at pos+1
5757     if (pos<plot_instructions.size())
5758       plot_instructions.erase(plot_instructions.begin()+pos,plot_instructions.end());
5759     if (param_group){
5760       param_group->redraw();
5761       int n=param_group->children(),i=0;
5762       for (;i<n;++i){
5763 	if (Gen_Value_Slider * gvs=dynamic_cast<Gen_Value_Slider *>(param_group->child(i))){
5764 	  if (gvs->pos>=int(pos))
5765 	    break;
5766 	}
5767       }
5768       for (;i<n;--n){
5769 	param_group->remove(param_group->child(n-1));
5770       }
5771     }
5772   }
5773 
handle(int event)5774   int Figure::handle(int event){
5775     if (event==FL_MOUSEWHEEL){
5776       if (!Fl::event_inside(this))
5777 	return 0;
5778       if (Fl::focus()==geo){
5779 	int res=geo->handle(event);
5780 	if (res)
5781 	  return res;
5782       }
5783       if (!Fl::event_inside(s))
5784 	return 0;
5785       return s->child(2)->handle(event);
5786     }
5787     return Fl_Tile::handle(event);
5788   }
5789 
rename(const string & s)5790   void Figure::rename(const string & s){
5791     if (namestr)
5792       delete namestr;
5793     string s1="Save "+s;
5794     namestr = new char[s1.size()+1];
5795     strcpy(namestr,s1.c_str());
5796     name->label(namestr);
5797     name->show();
5798   }
5799 
save_figure_as(const string & s_orig)5800   void Figure::save_figure_as(const string & s_orig){
5801     if (!geo->hp)
5802       return;
5803     string s(s_orig);
5804     if (s.empty()){
5805       // Get filename
5806       for (;;){
5807 	char * newfile = file_chooser(gettext("Save figure"), "*.cas", "session.cas");
5808 	if ( (!newfile) || (!*newfile))
5809 	  return;
5810 	s=newfile; // remove_path(newfile);
5811 	//s=remove_path(remove_extension(s.substr(0,1000).c_str()))+".cas";
5812 	s=remove_extension(s.substr(0,1000).c_str())+".cas";
5813 	if (access(s.c_str(),R_OK))
5814 	  break;
5815 	int i=fl_ask("%s",(s+gettext(": file exists. Overwrite?")).c_str());
5816 	if (i==1)
5817 	  break;
5818       }
5819     }
5820     rename(s);
5821     ofstream of(s.c_str());
5822     int n=geo->hp->children();
5823     // geo->hp->clear_modified();
5824     for (int i=0;i<n;i++){
5825       Fl_Widget * w = geo->hp->child(i);
5826       if (Fl_Group * g = dynamic_cast<Fl_Group *>(w)){
5827 	if (g->children()){
5828 	  w=g->child(0);
5829 	  if (Fl_Scroll * s =dynamic_cast<Fl_Scroll *>(w))
5830 	    w=s->child(0);
5831 	  if (Multiline_Input_tab * m=dynamic_cast<Multiline_Input_tab *>(w)){
5832 	    if (strlen(m->value()))
5833 	      of << replace(m->value(),'\n',' ')+";" << '\n';
5834 	  }
5835 	  if (Xcas_Text_Editor * m=dynamic_cast<Xcas_Text_Editor *>(w)){
5836 	    string s=m->value();
5837 	    if (!s.empty())
5838 	      of << replace(s,'\n',' ')+";" << '\n';
5839 	  }
5840 	}
5841       }
5842     }
5843   }
5844 
latex_save_figure()5845   std::string Figure::latex_save_figure(){
5846     static int nsession=0;
5847     nsession++;
5848     string thename="session"+print_INT_(nsession)+".tex";
5849     if (strlen(this->name->label())){
5850       thename=remove_extension(remove_path(this->name->label()))+".tex";
5851     }
5852     return geo->latex(thename.c_str());
5853   }
5854 
cb_Figure_Save(Fl_Widget * m,void *)5855   static void cb_Figure_Save(Fl_Widget * m , void*) {
5856     Figure * f=find_figure(m);
5857     if (f){
5858       if (f->namestr){
5859 	string tmp(f->namestr);
5860 	f->save_figure_as(tmp.substr(5,tmp.size()-5));
5861       }
5862       else
5863 	f->save_figure_as("");
5864     }
5865   }
5866 
cb_Figure_Save_as(Fl_Widget * m,void *)5867   static void cb_Figure_Save_as(Fl_Widget * m , void*) {
5868     Figure * f=find_figure(m);
5869     if (f)
5870       f->save_figure_as("");
5871   }
5872 
figure_insert(Figure * f)5873   std::string figure_insert(Figure * f){
5874     if (!f->geo->hp)
5875       return "";
5876     if (f){
5877       char * newfile = load_file_chooser(gettext("Insert figure"), "*.cas", "",0,false);
5878       if ( file_not_available(newfile))
5879 	return "";
5880       // Put newfile in selection and paste to f->geo->hp
5881       FILE * fich =fopen(newfile,"r");
5882       string s; char ch;
5883       for (;fich;){
5884 	ch=fgetc(fich);
5885 	if (feof(fich))
5886 	  break;
5887 	s += ch;
5888       }
5889       Fl::selection(*f,s.c_str(),s.size());
5890       Fl::focus(f->geo->hp);
5891       Fl::paste(*f->geo->hp);
5892       return newfile;
5893     }
5894     return "";
5895   }
5896 
cb_Figure_Insert(Fl_Widget * m,void *)5897   static void cb_Figure_Insert(Fl_Widget * m , void*) {
5898     Figure * f=find_figure(m);
5899     if (!f) return;
5900     figure_insert(f);
5901   }
5902 
cb_Figure_Preview(Fl_Widget * m,void *)5903   static void cb_Figure_Preview(Fl_Widget * m , void*) {
5904     Figure * f=find_figure(m);
5905     if (f)
5906       widget_ps_print(f->geo,remove_path(f->name->label()),true);
5907   }
5908 
cb_Figure_Print(Fl_Widget * m,void *)5909   static void cb_Figure_Print(Fl_Widget * m , void*) {
5910     Figure * f=find_figure(m);
5911     if (f)
5912       widget_print(f->geo);
5913   }
5914 
cb_Figure_LaTeX_Preview(Fl_Widget * m,void *)5915   static void cb_Figure_LaTeX_Preview(Fl_Widget * m , void*) {
5916     Figure * f=find_figure(m);
5917     if (f){
5918       string name=f->latex_save_figure();
5919       xdvi(name);
5920     }
5921   }
5922 
cb_Figure_LaTeX_Print(Fl_Widget * m,void *)5923   static void cb_Figure_LaTeX_Print(Fl_Widget * m , void*) {
5924     Figure * f=find_figure(m);
5925     if (f){
5926       string name=f->latex_save_figure();
5927       dvips(name);
5928     }
5929   }
5930 
5931 
figure_param_dialog(Fl_Widget * f,bool adjust,double & tmin,double & tmax,double & tcurrent,double & tstep,string & name,bool symb,string & tmp)5932   int figure_param_dialog(Fl_Widget * f,bool adjust,double & tmin,double & tmax,double & tcurrent,double & tstep,string & name,bool symb,string & tmp){
5933     static Fl_Window * w = 0;
5934     static Fl_Value_Input * wxmin=0, * wxmax=0, *wcurrent=0,*wstep=0;
5935     static Fl_Input * wname=0;
5936     static Fl_Check_Button * wsymb = 0 ;
5937     static Fl_Return_Button * button0 = 0 ; // ok
5938     static Fl_Button * button1 =0; // cancel
5939     static string paramname;
5940     if (f){
5941       if (!w){
5942 	int l=f->labelsize();
5943 	int dx=18*l,dy=6*l,dh=dy/3;
5944 	Fl_Group::current(0);
5945 	w=new Fl_Window(dx,dy);
5946 	wxmin=new Fl_Value_Input(dx/9,2,2*dx/9-2,dh-4,"t-");
5947 	wxmin->tooltip(gettext("Parameter minimal value"));
5948 	wxmin->value(-5);
5949 	wxmax=new Fl_Value_Input(dx/3+dx/9,2,2*dx/9-2,dh-4,"t+");
5950 	wxmax->tooltip(gettext("Parameter maximal value"));
5951 	wxmax->value(5);
5952 	wcurrent=new Fl_Value_Input(2*dx/3+dx/9,2,2*dx/9-2,dh-4,"t=");
5953 	wcurrent->tooltip(gettext("Parameter current value"));
5954 	wstep=new Fl_Value_Input(dx/6,2+dh,dx/6-2,dh-4,"step");
5955 	wstep->tooltip(gettext("Parameter step value"));
5956 	wstep->minimum(0);
5957 	wstep->maximum(1000);
5958 	wstep->step(0.001);
5959 	wstep->value(0.1);
5960 	wname=new Fl_Input(dx/2,2+dh,dx/6-2,dh-4,"name");
5961 	wname->tooltip(gettext("Parameter variable name"));
5962 	paramname="a";
5963 	wsymb=new Fl_Check_Button(2*dx/3+l+5,2+dh,l,dh-4,"symb");
5964 	wsymb->tooltip(gettext("Numeric or formal parameter"));
5965 	wsymb->value(true);
5966 	button0 = new Fl_Return_Button(2,2+2*dh,dx/2-4,dh-4);
5967 	button0->shortcut(0xff0d);
5968 	button0->label(gettext("OK"));
5969 	button1 = new Fl_Button(dx/2+2,2+ 2*dh,dx/2-4,dh-4);
5970 	button1->shortcut(0xff1b);
5971 	button1->label(gettext("Cancel"));
5972 	w->end();
5973 	change_group_fontsize(w,l);
5974 	w->resizable(w);
5975 	w->label(gettext("Parameter definition"));
5976       }
5977       if (adjust){
5978 	wxmin->value(tmin);
5979 	wxmax->value(tmax);
5980 	wcurrent->value(tcurrent);
5981 	wstep->value(tstep);
5982 	paramname=name;
5983 	wsymb->value(symb);
5984       }
5985       wname->value(paramname.c_str());
5986       w->set_modal();
5987       w->show();
5988       autosave_disabled=true;
5989       w->hotspot(w);
5990       Fl::focus(wxmin);
5991       int r;
5992       for (;;) {
5993 	Fl_Widget *o = Fl::readqueue();
5994 	if (!o) Fl::wait();
5995 	else {
5996 	  if (o == button0) {r = 0; break;}
5997 	  if (o == button1) {r = 1; break;}
5998 	  if (o == w) { r=1; break; }
5999 	}
6000       }
6001       w->hide();
6002       autosave_disabled=false;
6003       if (!r){ // insert parameter in figure pack
6004 	autoname_plus_plus(paramname);
6005 	name=wname->value();
6006 	tmin=wxmin->value();
6007 	tmax=wxmax->value();
6008 	tcurrent=wcurrent->value();
6009 	tstep=wstep->value();
6010 	if (wsymb->value())
6011 	  tmp="assume("+string(wname->value())+"=["+print_DOUBLE_(tcurrent)+","+print_DOUBLE_(tmin)+","+print_DOUBLE_(tmax)+","+print_DOUBLE_(tstep)+"])";
6012 	else
6013 	  tmp=string(wname->value())+" := element("+print_DOUBLE_(tmin)+".."+print_DOUBLE_(tmax)+","+print_DOUBLE_(tcurrent)+","+print_DOUBLE_(tstep)+")";
6014 	return 1;
6015       }
6016     } // end if (f)
6017     return 0;
6018   }
6019 
cb_Figure_Parameter(Fl_Widget * m,void *)6020   static void cb_Figure_Parameter(Fl_Widget * m , void*) {
6021     Fl_Widget * wid=Fl::focus();
6022     Figure * f=find_figure(m);
6023     if (f){
6024       if (!f->geo->hp)
6025 	return;
6026       string tmp,name;
6027       double tmin,tmax,tcur,tstep;
6028       if (figure_param_dialog(f,false,tmin,tmax,tcur,tstep,name,false,tmp)){
6029 	History_Pack * hp=f->geo->hp;
6030 	int pos;
6031 	if (hp!=get_history_pack(wid,pos))
6032 	  pos=hp->children()-1;
6033 	hp->add_entry(pos);
6034 	hp->set_value(pos,tmp,true);
6035       }
6036     }
6037   }
6038 
6039 
6040   // modeplot==0 (paramplot2d), 1 (paramplot3d), 2 (plotfield), 3 (implicit), -1 (polarplot)
plotparam_dialog(Fl_Widget * spread_ptr,std::string & arg,int modeplot)6041   int plotparam_dialog(Fl_Widget * spread_ptr,std::string & arg,int modeplot){
6042     static Fl_Window * w = 0;
6043     static Fl_Input *fcnxt=0, *fcnyt=0, *fcnrhot=0, *fcnxuv=0, *fcnyuv=0, *fcnzuv=0, *fcnfield=0, *fcnimplicit=0,*varnamet=0, * varnameu=0, * varnamev=0, *varnametfield=0,*varnameyfield=0,*varnamex=0,*varnamey=0;
6044     static Fl_Value_Input * tmin=0,*tstep=0,*tmax=0;
6045     static Fl_Value_Input * umin=0,*ustep=0,*umax=0;
6046     static Fl_Value_Input * vmin=0,*vstep=0,*vmax=0;
6047     static Fl_Value_Input * xmin=0,*xstep=0,*xmax=0;
6048     static Fl_Value_Input * ymin=0,*ystep=0,*ymax=0;
6049     static Fl_Return_Button * button0 = 0 ;
6050     static Fl_Button * button1 =0;
6051     static Fl_Check_Button * do_plotfield = 0,*do_normal=0,*do_autonome=0;
6052     static Line_Type *ltres=0;
6053     // static int curvestyle=0;
6054     Graph2d3d * gr = dynamic_cast<Graph2d3d *>(spread_ptr);
6055     if (!gr){
6056       if (Figure * fig=dynamic_cast<Figure *>(spread_ptr))
6057 	gr=fig->geo;
6058     }
6059     if (!w){
6060 #ifdef IPAQ
6061       int dx=240,dy=300;
6062 #else
6063       int dx=(spread_ptr?30*spread_ptr->labelsize():500),
6064 	dy=spread_ptr?12*spread_ptr->labelsize():400;
6065 #endif
6066       int lignes=5;
6067       Fl_Group::current(0);
6068       w=new Fl_Window(dx,dy);
6069       int l=spread_ptr->labelsize();
6070       ltres = new Line_Type(2,2,l,l,_MAGENTA+_CAP_FLAT_LINE);
6071       ltres->show_pnt(true);
6072       ltres->show_poly(true);
6073       do_plotfield= new Fl_Check_Button (l+2,2,dx/6-4-l,dy/lignes-4,"Field");
6074       do_plotfield->value(true);
6075       do_plotfield->tooltip(gettext("Draw slopefield"));
6076       do_autonome= new Fl_Check_Button (2+dx/6,2,dx/6-4,dy/lignes-4,"d=2");
6077       do_autonome->value(false);
6078       do_autonome->tooltip(gettext("Autonomous 2d systems."));
6079       do_normal= new Fl_Check_Button (2+dx/3,2,dx/6-4,dy/lignes-4,"||=1");
6080       do_normal->value(true);
6081       do_normal->tooltip(gettext("Normalize slopefield"));
6082       fcnimplicit=new Fl_Input(dx/2,2,dx/2-4,dy/lignes-4,gettext("F(x,y)="));
6083       fcnimplicit->value("x^4+y^4+x*y=25");
6084       fcnimplicit->tooltip(gettext("Implicit expression"));
6085       fcnfield=new Fl_Input(dx/2+dx/6,2,dx/2-dx/6-4,dy/lignes-4,gettext("dy/dt(t,y)="));
6086       fcnfield->value("sin(t*y)");
6087       fcnfield->tooltip(gettext("Expression of dy/dt in terms of y and t, e.g. sin(t*y). For autonomous 2d system,change time variable to x and enter d[x,y]/dt in terms of [x,y], e.g. [[1,2],[3,4]]*[x,y]"));
6088       fcnrhot=new Fl_Input(dx/2,2,dx/2-4,dy/lignes-4,gettext("rho(t)="));
6089       fcnrhot->value("2*t");
6090       fcnrhot->tooltip(gettext("Expression of modulus rho wrt to angle t (e.g sin(t))"));
6091       fcnxt=new Fl_Input(dx/4,2,dx/4-4,dy/lignes-4,gettext("x(t)="));
6092       fcnxt->value("sin(2*t)");
6093       fcnxt->tooltip(gettext("Expression of x wrt to t (e.g sin(t))"));
6094       fcnyt=new Fl_Input(3*dx/4,2,dx/4-4,dy/lignes-4,gettext("y(t)="));
6095       fcnyt->value("cos(3*t)");
6096       fcnyt->tooltip(gettext("Expression of y wrt to t (e.g cos(t))"));
6097       fcnxuv=new Fl_Input(dx/6,2,dx/6-4,dy/lignes-4,gettext("x="));
6098       fcnxuv->value("u+v^2");
6099       fcnxuv->tooltip(gettext("Expression of x wrt to u and v (e.g. u+v)"));
6100       fcnyuv=new Fl_Input(3*dx/6,2,dx/6-4,dy/lignes-4,gettext("y="));
6101       fcnyuv->value("cos(u)+v");
6102       fcnyuv->tooltip(gettext("Expression of y wrt to u and v (e.g exp(u)-v)"));
6103       fcnzuv=new Fl_Input(5*dx/6,2,dx/6-4,dy/lignes-4,gettext("y="));
6104       fcnzuv->value("sin(u)+v");
6105       fcnzuv->tooltip(gettext("Expression of z wrt to u and v (e.g u-v)"));
6106       varnamet=new Fl_Input(dx/2,2+dy/lignes,dx/2-4,dy/lignes-4,gettext("Var"));
6107       varnamet->value("t");
6108       varnamet->tooltip(gettext("Independant variable name (e.g t)"));
6109       varnameu=new Fl_Input(dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("1st var"));
6110       varnameu->value("u");
6111       varnameu->tooltip(gettext("First independant variable name (e.g u)"));
6112       varnamev=new Fl_Input(3*dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("2nd var"));
6113       varnamev->value("v");
6114       varnamev->tooltip(gettext("Second independant variable name (e.g v)"));
6115       varnamex=new Fl_Input(dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("1st var"));
6116       varnamex->value("x");
6117       varnamex->tooltip(gettext("First independant variable name (e.g x)"));
6118       varnamey=new Fl_Input(3*dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("2nd var"));
6119       varnamey->value("y");
6120       varnamey->tooltip(gettext("Second independant variable name (e.g y)"));
6121       varnametfield=new Fl_Input(dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("Time var"));
6122       varnametfield->value("t");
6123       varnametfield->tooltip(gettext("Time variable name"));
6124       varnameyfield=new Fl_Input(3*dx/4,2+dy/lignes,dx/4-4,dy/lignes-4,gettext("2nd var"));
6125       varnameyfield->value("y");
6126       varnameyfield->tooltip(gettext("Function variable name"));
6127       tmin = new Fl_Value_Input(dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("tmin"));
6128       tmin->value(-3.14);
6129       tmin->step(0.5);
6130       tstep = new Fl_Value_Input(3*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("tstep"));
6131       tstep->value(0.1);
6132       tstep->step(0.01);
6133       tmax = new Fl_Value_Input(5*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("tmax"));
6134       tmax->value(3.14);
6135       tmax->step(0.5);
6136       umin = new Fl_Value_Input(dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("umin"));
6137       umin->value(-4);
6138       umin->step(0.5);
6139       ustep = new Fl_Value_Input(3*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("ustep"));
6140       ustep->value(0.5);
6141       ustep->step(0.01);
6142       umax = new Fl_Value_Input(5*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("umax"));
6143       umax->value(4);
6144       umax->step(0.5);
6145       vmin = new Fl_Value_Input(dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("vmin"));
6146       vmin->value(-4);
6147       vmin->step(0.5);
6148       vstep = new Fl_Value_Input(3*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("vstep"));
6149       vstep->value(0.5);
6150       vstep->step(0.01);
6151       vmax = new Fl_Value_Input(5*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("vmax"));
6152       vmax->value(4);
6153       vmax->step(0.5);
6154       xmin = new Fl_Value_Input(dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xmin"));
6155       xmin->value(-5);
6156       xmin->step(0.5);
6157       xstep = new Fl_Value_Input(3*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xstep"));
6158       xstep->value(0.1);
6159       xstep->step(0.01);
6160       xmax = new Fl_Value_Input(5*dx/6,2+2*dy/lignes,dx/6-2,dy/lignes-4,gettext("xmax"));
6161       xmax->value(5);
6162       xmax->step(0.5);
6163       ymin = new Fl_Value_Input(dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ymin"));
6164       ymin->value(-5);
6165       ymin->step(0.5);
6166       ystep = new Fl_Value_Input(3*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ystep"));
6167       ystep->value(0.1);
6168       ystep->step(0.01);
6169       ymax = new Fl_Value_Input(5*dx/6,2+3*dy/lignes,dx/6-2,dy/lignes-4,gettext("ymax"));
6170       ymax->value(5);
6171       ymax->step(0.5);
6172       button0 = new Fl_Return_Button(2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
6173       button0->shortcut(0xff0d);
6174       button0->label(gettext("OK"));
6175       button1 = new Fl_Button(dx/2+2,2+4*dy/lignes,dx/2-4,dy/lignes-4);
6176       button1->shortcut(0xff1b);
6177       button1->label(gettext("Cancel"));
6178       w->end();
6179       change_group_fontsize(w,spread_ptr?spread_ptr->labelsize():14);
6180       w->resizable(w);
6181     }
6182     switch (modeplot){
6183     case -1:
6184       w->label(gettext("Polar plot"));
6185       break;
6186     case 0: case 1:
6187       w->label(gettext("Parametric plot"));
6188       break;
6189     case 2:
6190       w->label(gettext("Field/Odeplot"));
6191       break;
6192     case 3:
6193       w->label(gettext("Implicitplot"));
6194       break;
6195     }
6196     fcnxt->hide();
6197     fcnyt->hide();
6198     fcnrhot->hide();
6199     fcnxuv->hide();
6200     fcnyuv->hide();
6201     fcnzuv->hide();
6202     fcnfield->hide();
6203     fcnimplicit->hide();
6204     varnamet->hide();
6205     varnameu->hide();
6206     varnamev->hide();
6207     varnamex->hide();
6208     varnamey->hide();
6209     varnametfield->hide();
6210     varnameyfield->hide();
6211     tmax->hide();
6212     tmin->hide();
6213     tstep->hide();
6214     umax->hide();
6215     umin->hide();
6216     ustep->hide();
6217     vmax->hide();
6218     vmin->hide();
6219     vstep->hide();
6220     xmax->hide();
6221     xmin->hide();
6222     xstep->hide();
6223     ymax->hide();
6224     ymin->hide();
6225     ystep->hide();
6226     do_plotfield->hide();
6227     do_normal->hide();
6228     do_autonome->hide();
6229     if (modeplot>=2){
6230       xmin->show();
6231       xstep->show();
6232       xmax->show();
6233       ymin->show();
6234       ystep->show();
6235       ymax->show();
6236       if (modeplot==2){
6237 	varnametfield->show();
6238 	varnameyfield->show();
6239 	fcnfield->show();
6240 	do_plotfield->show();
6241 	do_normal->show();
6242 	do_autonome->show();
6243       }
6244       else {
6245 	varnamex->show();
6246 	varnamey->show();
6247 	fcnimplicit->show();
6248       }
6249     }
6250     if (modeplot==1){
6251       umax->show();
6252       umin->show();
6253       ustep->show();
6254       vmax->show();
6255       vmin->show();
6256       vstep->show();
6257       varnameu->show();
6258       varnamev->show();
6259       fcnxuv->show();
6260       fcnyuv->show();
6261       fcnzuv->show();
6262     }
6263     if (modeplot<=0) {
6264       tmax->show();
6265       tmin->show();
6266       tstep->show();
6267       varnamet->show();
6268       if (modeplot==-1){
6269 	fcnrhot->show();
6270 	tmin->value(0.0);
6271       }
6272       else {
6273 	fcnxt->show();
6274 	fcnyt->show();
6275       }
6276     }
6277     if (gr) {
6278       if (!gr->fcnfield.empty())
6279 	fcnfield->value(gr->fcnfield.c_str());
6280       xmin->value(gr->window_xmin);
6281       xmax->value(gr->window_xmax);
6282       xstep->value((xmax->value()-xmin->value())/64);
6283       ymin->value(gr->window_xmin);
6284       ymax->value(gr->window_xmax);
6285       ystep->value((xmax->value()-xmin->value())/64);
6286     }
6287     int r=-1;
6288     w->set_modal();
6289     w->show();
6290     autosave_disabled=true;
6291     w->hotspot(w);
6292     Fl::focus(button0);
6293     for (;;) {
6294       Fl_Widget *o = Fl::readqueue();
6295       if (!o) Fl::wait();
6296       else {
6297 	if (o==ltres){
6298 	  int i=ltres->line_type();
6299 	  bool formel=false,untranslate=false,approx=false;
6300 	  change_line_type(i,true,approx,"",fcnzuv->visible(),formel,untranslate,false,spread_ptr?spread_ptr->labelsize():14);
6301 	  ltres->line_type(i);
6302 	}
6303 	if (o==do_autonome){
6304 	  if (do_autonome->value()){
6305 	    fcnfield->value("[[1,2],[3,4]]*[x,y]");
6306 	    varnametfield->value("x");
6307 	    varnameyfield->value("y");
6308 	  }
6309 	  else {
6310 	    fcnfield->value("sin(t*y)");
6311 	    varnametfield->value("t");
6312 	    varnameyfield->value("y");
6313 	  }
6314 	}
6315 	if (o == button0) {r = 0; break;}
6316 	if (o == button1) {r = 1; break;}
6317 	if (o == w) { r=1; break; }
6318       }
6319     }
6320     autosave_disabled=false;
6321     w->hide();
6322     if (!r){
6323       if (modeplot==3){
6324 	arg=string(fcnimplicit->value())+",["+string(varnamex->value())+"="+print_DOUBLE_(xmin->value())+".."+print_DOUBLE_(xmax->value()) + string(",")+varnamey->value()+string("=")+print_DOUBLE_(ymin->value())+".."+print_DOUBLE_(ymax->value())+"],xstep="+print_DOUBLE_(xstep->value())+",ystep="+print_DOUBLE_(ystep->value())+",display="+print_color(ltres->line_type());
6325 	return 1;
6326       }
6327       if (modeplot==2){
6328 	if (gr){
6329 	  gr->fcnfield=fcnfield->value();
6330 	  gr->fcnvars="["+string(varnametfield->value())+","+string(varnameyfield->value())+"]";
6331 	}
6332 	arg=string(fcnfield->value())+",["+string(varnametfield->value())+"="+print_DOUBLE_(xmin->value())+".."+print_DOUBLE_(xmax->value()) + string(",")+varnameyfield->value()+string("=")+print_DOUBLE_(ymin->value())+".."+print_DOUBLE_(ymax->value())+"]";
6333 	if (do_normal->value())
6334 	  arg+=",normalize";
6335 	arg+= ",xstep="+print_DOUBLE_(xstep->value())+",ystep="+print_DOUBLE_(ystep->value())+",display="+print_color(ltres->line_type());
6336 	return do_plotfield->value()?2:1;
6337       }
6338       if (modeplot==1) {
6339 	arg = "["+string(fcnxuv->value())+","+string(fcnyuv->value())+","+string(fcnzuv->value())+"]";
6340 	arg += ",\n["+string(varnameu->value())+"="+print_DOUBLE_(umin->value())+".."+print_DOUBLE_(umax->value()) + string(",")+varnamev->value()+string("=")+print_DOUBLE_(vmin->value())+".."+print_DOUBLE_(vmax->value())+"],\nustep="+print_DOUBLE_(ustep->value())+",vstep="+print_DOUBLE_(vstep->value())+",display="+print_color(ltres->line_type());
6341 	return 1;
6342       }
6343       if (modeplot==-1)
6344 	arg = string(fcnrhot->value())+",";
6345       else
6346 	arg = "["+string(fcnxt->value())+","+string(fcnyt->value())+"]\n,";
6347       arg += string(varnamet->value())+"="+print_DOUBLE_(tmin->value())+".."+print_DOUBLE_(tmax->value())+",tstep="+print_DOUBLE_(tstep->value())+",display="+print_color(ltres->line_type());
6348       return 1;
6349     }
6350     return 0;
6351   }
6352 
multiline_focus_error()6353   void multiline_focus_error(){
6354     fl_alert("%s",gettext("Click first in a commandline"));
6355   }
6356 
cb_Figure_Function(Fl_Widget * m,void *)6357   static void cb_Figure_Function(Fl_Widget * m , void*) {
6358     Fl_Widget * wid=Xcas_input_focus;
6359     Figure * f=find_figure(wid);
6360     if (f){
6361       string arg;
6362       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6363       if (f && tablefunc_dialog(f,arg,true,(dim3?1:0),gettext("Graph of a function"))){
6364 	History_Pack * hp=f->geo->hp;
6365 	int pos;
6366 	if (hp!=get_history_pack(wid,pos))
6367 	  pos=hp->children()-1;
6368 	hp->add_entry(pos);
6369 	// arg=autoname(hp->contextptr)+(dim3?":= plotfunc(":":=plot(")+arg+")";
6370 	arg=autoname(hp->contextptr)+":=plot("+arg+")";
6371 	f->geo->autoname_plus_plus();
6372 	hp->set_value(pos,arg,true);
6373       }
6374       else Fl::focus(wid);
6375     }
6376   }
6377 
cb_Figure_helpon(Fl_Widget * m,const string & cmd)6378   static void cb_Figure_helpon(Fl_Widget * m ,const string & cmd) {
6379     Fl_Widget * wid=Xcas_input_focus;
6380     Figure * f=find_figure(wid);
6381     if (f){
6382       string ans;
6383       int remove=0;
6384       int r;
6385       if (do_helpon)
6386 	r=handle_tab(cmd,*giac::vector_completions_ptr(),2*f->w()/3,2*f->h()/3,remove,ans);
6387       else {
6388 	ans=cmd+"()";
6389 	r=1;
6390       }
6391       if (r){
6392 	if (!f->geo->hp)
6393 	  return;
6394 	History_Pack * hp=f->geo->hp;
6395 	int pos;
6396 	if (hp!=get_history_pack(wid,pos))
6397 	  pos=hp->children()-1;
6398 	hp->add_entry(pos);
6399 	hp->set_value(pos,ans,false);
6400       }
6401       else Fl::focus(wid);
6402     }
6403   }
6404 
cb_Figure_Tangent(Fl_Widget * m,void *)6405   static void cb_Figure_Tangent(Fl_Widget * m , void*) {
6406     // cb_set_mode(m,at_segment,at_tangent,2,gettext("Curve,Point"));
6407     cb_Figure_helpon(m,"tangent");
6408   }
6409 
cb_Figure_Implicit(Fl_Widget * m,void *)6410   static void cb_Figure_Implicit(Fl_Widget * m , void*) {
6411     Fl_Widget * wid=Xcas_input_focus;
6412     Figure * f=find_figure(wid);
6413     if (f){
6414       if (!f->geo->hp)
6415 	return;
6416       string arg;
6417       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6418       if (dim3)
6419 	fl_message("%s","Currently limited to 2-d");
6420       else {
6421 	if (f && plotparam_dialog(f,arg,3)){
6422 	  History_Pack * hp=f->geo->hp;
6423 	  int pos;
6424 	  if (hp!=get_history_pack(wid,pos))
6425 	    pos=hp->children()-1;
6426 	  hp->add_entry(pos);
6427 	  arg=autoname(hp->contextptr)+":=plotimplicit("+arg+")";
6428 	  f->geo->autoname_plus_plus();
6429 	  hp->set_value(pos,arg,true);
6430 	}
6431 	else Fl::focus(wid);
6432       }
6433     }
6434   }
6435 
cb_Figure_Plotfield(Fl_Widget * m,void *)6436   static void cb_Figure_Plotfield(Fl_Widget * m , void*) {
6437     Fl_Widget * wid=Xcas_input_focus;
6438     Figure * f=find_figure(wid);
6439     if (f){
6440       if (!f->geo->hp)
6441 	return;
6442       string arg;
6443       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6444       int res;
6445       if (dim3)
6446 	fl_message("%s","Currently limited to 2-d");
6447       else {
6448 	if (f && (res=plotparam_dialog(f,arg,2))){
6449 	  if (res==2){
6450 	    History_Pack * hp=f->geo->hp;
6451 	    int pos;
6452 	    if (hp!=get_history_pack(wid,pos))
6453 	      pos=hp->children()-1;
6454 	    hp->add_entry(pos);
6455 	    arg="plotfield("+arg+")";
6456 	    hp->set_value(pos,arg,true);
6457 	  }
6458 	  cb_set_mode(f,0,at_plotode,1,gettext("Point_on_ode_curve"));
6459 	  fl_message("%s",gettext("Click initials conditions in graphic window. Change mode when finished."));
6460 	}
6461 	else Fl::focus(wid);
6462       }
6463     }
6464   }
6465 
cb_plotode(Fl_Widget * m,void *)6466   static void cb_plotode(Fl_Widget * m , void*) {
6467     Figure * f=find_figure(m);
6468     if (f){
6469       if (f->geo->fcnfield.empty())
6470 	cb_Figure_Plotfield(m,0);
6471       else
6472 	cb_set_mode(m,0,at_plotode,1,gettext("Point_on_ode_curve"));
6473     }
6474   }
6475 
cb_Figure_Param(Fl_Widget * m,void *)6476   static void cb_Figure_Param(Fl_Widget * m , void*) {
6477     Fl_Widget * wid=Xcas_input_focus;
6478     Figure * f=find_figure(wid);
6479     if (f){
6480       if (!f->geo->hp)
6481 	return;
6482       string arg;
6483       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6484       if (f && plotparam_dialog(f,arg,(dim3?1:0))){
6485 	History_Pack * hp=f->geo->hp;
6486 	int pos;
6487 	if (hp!=get_history_pack(wid,pos))
6488 	  pos=hp->children()-1;
6489 	hp->add_entry(pos);
6490 	arg=autoname(hp->contextptr)+":=plotparam("+arg+")";
6491 	f->geo->autoname_plus_plus();
6492 	hp->set_value(pos,arg,true);
6493       }
6494       else Fl::focus(wid);
6495     }
6496   }
6497 
cb_Figure_Polar(Fl_Widget * m,void *)6498   static void cb_Figure_Polar(Fl_Widget * m , void*) {
6499     Fl_Widget * wid=Xcas_input_focus;
6500     Figure * f=find_figure(wid);
6501     if (f){
6502       if (!f->geo->hp)
6503 	return;
6504       string arg;
6505       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6506       if (dim3)
6507 	fl_alert("%s","Not a 3-d graph");
6508       else {
6509 	if (f && plotparam_dialog(f,arg,-1)){
6510 	  History_Pack * hp=f->geo->hp;
6511 	  int pos;
6512 	  if (hp!=get_history_pack(wid,pos))
6513 	    pos=hp->children()-1;
6514 	  hp->add_entry(pos);
6515 	  arg=autoname(hp->contextptr)+":=plotpolar("+arg+")";
6516 	  f->geo->autoname_plus_plus();
6517 	  hp->set_value(pos,arg,true);
6518 	}
6519 	else Fl::focus(wid);
6520       }
6521     }
6522   }
6523 
cb_Figure_Plotarea(Fl_Widget * m,void *)6524   static void cb_Figure_Plotarea(Fl_Widget * m , void*) {
6525     Fl_Widget * wid=Xcas_input_focus;
6526     Figure * f=find_figure(wid);
6527     if (f){
6528       if (!f->geo->hp)
6529 	return;
6530       string arg;
6531       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6532       if (dim3)
6533 	fl_alert("%s","Not a 3-d graph");
6534       else {
6535 	if (f && tablefunc_dialog(f,arg,true,2,gettext("Shade area under a curve"))){
6536 	  History_Pack * hp=f->geo->hp;
6537 	  int pos;
6538 	  if (hp!=get_history_pack(wid,pos))
6539 	    pos=hp->children()-1;
6540 	  hp->add_entry(pos);
6541 	  arg="plotarea("+arg+")";
6542 	  hp->set_value(pos,arg,true);
6543 	}
6544 	else Fl::focus(wid);
6545       }
6546     }
6547   }
6548 
cb_Figure_Sequence(Fl_Widget * m,void *)6549   static void cb_Figure_Sequence(Fl_Widget * m , void*) {
6550     Fl_Widget * wid=Xcas_input_focus;
6551     Figure * f=find_figure(wid);
6552     if (f){
6553       if (!f->geo->hp)
6554 	return;
6555       string arg,u0param;
6556       bool dim3=dynamic_cast<Graph3d *>(f->geo);
6557       if (dim3)
6558 	fl_alert("%s","Not a 2-d graph");
6559       else {
6560 	if (f && tableseq_dialog(f,arg,true,gettext("Graph of a recurrent sequence"),u0param)){
6561 	  History_Pack * hp=f->geo->hp;
6562 	  int pos;
6563 	  if (hp!=get_history_pack(wid,pos))
6564 	    pos=hp->children()-1;
6565 	  hp->add_entry(pos);
6566 	  arg="plotseq("+arg+")";
6567 	  hp->set_value(pos,arg,false);
6568 	  hp->add_entry(pos);
6569 	  hp->set_value(pos,u0param,true);
6570 	}
6571 	else Fl::focus(wid);
6572       }
6573     }
6574   }
6575 
6576   /* model for new callbacks
6577   static void cb_Figure(Fl_Widget * m , void*) {
6578     Figure * f=find_figure(m);
6579     if (f){
6580     }
6581   }
6582   */
6583 
contrast(Fl_Color c)6584   int contrast(Fl_Color c){
6585     if (c<=7)
6586       return 7-c;
6587     if (c>=8 && c<0x10)
6588       return 7;
6589     if (c>=0x10 && c<0x50)
6590       return 0xf8;
6591     if (c & 0x4)
6592       return 0;
6593     return 7;
6594   }
6595 
cb_Figure_Color(Fl_Button * b,void *)6596   static void cb_Figure_Color(Fl_Button * b , void*) {
6597     static string s;
6598     Figure * f=find_figure(b);
6599     if (f){
6600       Fl_Color col=b->color();
6601       col=fl_show_colormap(col);
6602       f->couleur->color(col);
6603       Fl_Color col2=Fl_Color(contrast(col));
6604       f->couleur->labelcolor(col2);
6605       s=col<1000?print_INT_(col):"";
6606       f->couleur->label(s.c_str());
6607       f->geo->couleur=(col&0xffff) | (f->geo->couleur & 0xffff0000);
6608       f->lt->line_type(f->geo->couleur);
6609     }
6610   }
6611 
cb_Figure_Disposition(Fl_Button * b,void *)6612   static void cb_Figure_Disposition(Fl_Button * b , void*) {
6613     Figure * fig=find_figure(b);
6614     if (!fig) return;
6615     fig->disposition=b->value();
6616     fig->resize(fig->x(),fig->y(),fig->w(),fig->h());
6617     fig->geo->orthonormalize();
6618     fig->redraw();
6619   }
6620 
cb_Figure_Approx(Fl_Button * b,void *)6621   static void cb_Figure_Approx(Fl_Button * b , void*) {
6622     Figure * fig=find_figure(b);
6623     if (!fig) return;
6624     fig->geo->approx=b->value();
6625   }
6626 
cb_Figure_Autoeval(Fl_Button * b,void *)6627   static void cb_Figure_Autoeval(Fl_Button * b , void*) {
6628     static string s;
6629     Figure * f=find_figure(b);
6630     if (!f) return;
6631     f->geo->hp->eval_below=!b->value();
6632     f->geo->clear();
6633     if (!f->geo->hp->children())
6634       return;
6635     f->geo->hp->focus(0,true);
6636   }
6637 
cb_Exact(Fl_Button * b,void *)6638   static void cb_Exact(Fl_Button * b , void*) {
6639     Figure * f=find_figure(b);
6640     if (f){
6641       f->geo->approx=false;
6642     }
6643   }
6644 
cb_Approx(Fl_Button * b,void *)6645   static void cb_Approx(Fl_Button * b , void*) {
6646     Figure * f=find_figure(b);
6647     if (f){
6648       f->geo->approx=true;
6649     }
6650   }
6651 
cb_Figure_Line_Type(Fl_Widget * b,void *)6652   static void cb_Figure_Line_Type(Fl_Widget * b , void*) {
6653     static string s;
6654     Figure * f=find_figure(b);
6655     if (f){
6656       int i=f->lt->line_type();
6657       bool formel=false,untranslate=false;
6658       change_line_type(i,true,f->geo->approx," (next mouse created objects)",(dynamic_cast<Graph3d *>(f->geo)),formel,untranslate,false,f->geo->labelsize());
6659       Fl_Color col = Fl_Color(i&0xffff);
6660       f->couleur->color(col);
6661       Fl_Color col2=Fl_Color(contrast(col));
6662       f->couleur->labelcolor(col2);
6663       s=col<1000?print_INT_(col):"";
6664       f->couleur->label(s.c_str());
6665       f->lt->line_type(i);
6666       f->geo->couleur=i;
6667     }
6668   }
6669 
cb_Figure_Portrait(Fl_Widget * b,void *)6670   static void cb_Figure_Portrait(Fl_Widget * b , void*) {
6671     Figure * f=find_figure(b);
6672     if (f){
6673       f->disposition=0;
6674       f->resize(f->x(),f->y(),f->w(),f->h());
6675       f->geo->orthonormalize();
6676       f->redraw();
6677     }
6678   }
6679 
cb_Figure_Landscape(Fl_Widget * b,void *)6680   static void cb_Figure_Landscape(Fl_Widget * b , void*) {
6681     Figure * f=find_figure(b);
6682     if (f){
6683       f->disposition=1;
6684       f->resize(f->x(),f->y(),f->w(),f->h());
6685       f->geo->orthonormalize();
6686       f->redraw();
6687     }
6688   }
6689 
cb_Figure_Focus(Fl_Widget * b,void *)6690   static void cb_Figure_Focus(Fl_Widget * b , void*) {
6691     Figure * f=find_figure(b);
6692     if (f){
6693       f->geo->handle(FL_FOCUS);
6694     }
6695   }
6696 
cb_Figure_Change_Attributs(Fl_Widget * b,void *)6697   static void cb_Figure_Change_Attributs(Fl_Widget * b , void*) {
6698     Figure * f=find_figure(b);
6699     if (!f) return;
6700     if (!f->geo->hp)
6701       return;
6702     if (f && f->geo && f->geo->hp){
6703       int hp_pos=f->geo->hp->_sel_begin;
6704       f->geo->change_attributs(hp_pos);
6705     }
6706   }
6707 
cb_NumericalEdit(Fl_Widget * b,void *)6708   static void cb_NumericalEdit(Fl_Widget * b , void*) {
6709     Figure * f=find_figure(b);
6710     if (!f) return;
6711     if (!f->geo->hp)
6712       return;
6713     if (f && f->geo && f->geo->hp){
6714       History_Pack * hp =f->geo->hp;
6715       const char * ch=fl_input(gettext("Real number?"),"1");
6716       static string s;
6717       if (ch){
6718 	double n=atof(ch);
6719 	gen g=symbolic(at_legende,makevecteur(gen(f->geo->window_xmin+(f->geo->window_xmax-f->geo->window_xmin)/20,f->geo->window_ymin+(f->geo->window_ymax-f->geo->window_ymin)/20),n));
6720 	gen pntname(autoname(hp->contextptr),hp->contextptr);
6721 	g=symbolic(at_sto,gen(makevecteur(g,pntname),_SEQ__VECT));
6722 	f->geo->autoname_plus_plus();
6723 	f->geo->hp->set_gen_value(-1,g);
6724       }
6725     }
6726   }
6727 
dim3(Fl_Widget * m)6728   bool dim3(Fl_Widget * m){
6729     Figure * f=find_figure(m);
6730     if (f && f->geo)
6731       return dynamic_cast<Graph3d *>(f->geo);
6732     else
6733       return false;
6734   }
6735 
cb_Frame(Fl_Widget * m,void *)6736   static void cb_Frame(Fl_Widget * m , void*) {
6737     cb_set_mode(m,0,0,255," object_selects_level");
6738   }
6739 
cb_Pointer(Fl_Widget * m,void *)6740   static void cb_Pointer(Fl_Widget * m , void*) {
6741     cb_set_mode(m,0,0,0," point_to_move");
6742   }
6743 
cb_Point(Fl_Widget * m,void *)6744   static void cb_Point(Fl_Widget * m , void*) {
6745     cb_set_mode(m,0,at_point,1,"Point");
6746   }
6747 
cb_Circle(Fl_Widget * m,void *)6748   static void cb_Circle(Fl_Widget * m , void*) {
6749     cb_set_mode(m,at_segment,at_cercle,(dim3(m)?3:2),(dim3(m)?gettext("Center,Point_on_circle,Point_in_plane"):gettext("Center,Point_on_circle")));
6750   }
6751 
cb_Inter_Unique(Fl_Widget * m,void *)6752   static void cb_Inter_Unique(Fl_Widget * m , void*) {
6753     cb_set_mode(m,at_segment,at_inter_unique,2,gettext("Curve1,Curve2"));
6754   }
6755 
cb_Inter(Fl_Widget * m,void *)6756   static void cb_Inter(Fl_Widget * m , void*) {
6757     cb_set_mode(m,at_segment,at_inter,2,gettext("Curve1,Curve2"));
6758   }
6759 
cb_Inter_3(Fl_Widget * m,void *)6760   static void cb_Inter_3(Fl_Widget * m , void*) {
6761     cb_set_mode(m,at_polygone_ouvert,at_inter,3,gettext("Curve1,Curve2,Point"));
6762   }
6763 
cb_Tangent(Fl_Widget * m,void *)6764   static void cb_Tangent(Fl_Widget * m , void*) {
6765     cb_set_mode(m,at_segment,at_tangent,2,gettext("Curve,Point"));
6766   }
6767 
cb_Segment(Fl_Widget * m,void *)6768   static void cb_Segment(Fl_Widget * m , void*) {
6769     cb_set_mode(m,at_segment,at_segment,2,gettext("Point1,Point2"));
6770   }
6771 
cb_Vector(Fl_Widget * m,void *)6772   static void cb_Vector(Fl_Widget * m , void*) {
6773     cb_set_mode(m,at_vector,at_vector,2,gettext("Point1,Point2"));
6774   }
6775 
cb_Demi_Droite(Fl_Widget * m,void *)6776   static void cb_Demi_Droite(Fl_Widget * m , void*) {
6777     cb_set_mode(m,at_demi_droite,at_demi_droite,2,gettext("Point1,Point2"));
6778   }
6779 
cb_Droite(Fl_Widget * m,void *)6780   static void cb_Droite(Fl_Widget * m , void*) {
6781     cb_set_mode(m,at_droite,at_droite,2,gettext("Point1,Point2"));
6782   }
6783 
cb_DistanceAB(Fl_Widget * m,void *)6784   static void cb_DistanceAB(Fl_Widget * m , void*) {
6785     cb_set_mode(m,at_segment,at_distanceat,3,gettext("Object1,Object2,Position"));
6786   }
cb_DistanceABraw(Fl_Widget * m,void *)6787   static void cb_DistanceABraw(Fl_Widget * m , void*) {
6788     cb_set_mode(m,at_segment,at_distanceatraw,3,gettext("Object1,Object2,Position"));
6789   }
6790 
cb_AngleABC(Fl_Widget * m,void *)6791   static void cb_AngleABC(Fl_Widget * m , void*) {
6792     cb_set_mode(m,at_triangle,at_angleat,4,gettext("Angle_vertex,Direction1,Direction2,Position"));
6793   }
cb_AngleABCraw(Fl_Widget * m,void *)6794   static void cb_AngleABCraw(Fl_Widget * m , void*) {
6795     cb_set_mode(m,at_triangle,at_angleatraw,4,gettext("Angle_vertex,Direction1,Direction2,Position"));
6796   }
6797 
cb_Arearaw(Fl_Widget * m,void *)6798   static void cb_Arearaw(Fl_Widget * m , void*) {
6799     cb_set_mode(m,at_areaatraw,at_areaatraw,2,gettext("Object,Position"));
6800   }
6801 
cb_Area(Fl_Widget * m,void *)6802   static void cb_Area(Fl_Widget * m , void*) {
6803     cb_set_mode(m,at_areaat,at_areaat,2,gettext("Object,Position"));
6804   }
6805 
cb_Perimeterraw(Fl_Widget * m,void *)6806   static void cb_Perimeterraw(Fl_Widget * m , void*) {
6807     cb_set_mode(m,at_perimeteratraw,at_perimeteratraw,2,gettext("Object,Position"));
6808   }
6809 
cb_Perimeter(Fl_Widget * m,void *)6810   static void cb_Perimeter(Fl_Widget * m , void*) {
6811     cb_set_mode(m,at_perimeterat,at_perimeterat,2,gettext("Object,Position"));
6812   }
6813 
cb_Sloperaw(Fl_Widget * m,void *)6814   static void cb_Sloperaw(Fl_Widget * m , void*) {
6815     cb_set_mode(m,at_slopeatraw,at_slopeatraw,2,gettext("Object,Position"));
6816   }
6817 
cb_Slope(Fl_Widget * m,void *)6818   static void cb_Slope(Fl_Widget * m , void*) {
6819     cb_set_mode(m,at_slopeat,at_slopeat,2,gettext("Object,Position"));
6820   }
6821 
cb_Symetrie(Fl_Widget * m,void *)6822   static void cb_Symetrie(Fl_Widget * m , void*) {
6823     cb_set_mode(m,at_segment,at_symetrie,2,gettext("Symmetry_center_axis,Object"));
6824   }
6825 
cb_Inversion(Fl_Widget * m,void *)6826   static void cb_Inversion(Fl_Widget * m , void*) {
6827     cb_set_mode(m,at_segment,at_inversion,3,gettext("Center,Ratio,Object"));
6828   }
6829 
cb_Projection(Fl_Widget * m,void *)6830   static void cb_Projection(Fl_Widget * m , void*) {
6831     cb_set_mode(m,at_segment,at_projection,2,gettext("Curve,Object"));
6832   }
6833 
cb_Reciprocation(Fl_Widget * m,void *)6834   static void cb_Reciprocation(Fl_Widget * m , void*) {
6835     cb_set_mode(m,at_segment,at_polaire_reciproque,2,gettext("Circle,Object"));
6836   }
6837 
cb_Rotation(Fl_Widget * m,void *)6838   static void cb_Rotation(Fl_Widget * m , void*) {
6839     cb_set_mode(m,at_polygone_ouvert,at_rotation,3,gettext("Center,Angle,Object"));
6840   }
6841 
cb_Homothetie(Fl_Widget * m,void *)6842   static void cb_Homothetie(Fl_Widget * m , void*) {
6843     cb_set_mode(m,at_polygone_ouvert,at_homothetie,3,gettext("Center,Ratio,Object"));
6844   }
6845 
cb_Translation(Fl_Widget * m,void *)6846   static void cb_Translation(Fl_Widget * m , void*) {
6847     cb_set_mode(m,at_segment,at_translation,2,gettext("Vector,Object"));
6848   }
6849 
cb_Similitude(Fl_Widget * m,void *)6850   static void cb_Similitude(Fl_Widget * m , void*) {
6851     cb_set_mode(m,at_polygone_ouvert,at_similitude,4,gettext("Center,Ratio,Angle,Object"));
6852   }
6853 
cb_Polygone(Fl_Widget * m,void *)6854   static void cb_Polygone(Fl_Widget * m , void*) {
6855     const char * ch=fl_input(gettext("Number of vertices?"),"5");
6856     static string s;
6857     if (ch){
6858       int n=atoi(ch);
6859       s="";
6860       if (n>=2){
6861 	for (int i=1;i<=n;++i){
6862 	  s+=gettext("Point")+print_INT_(i);
6863 	  if (i<n)
6864 	    s+=",";
6865 	}
6866 	cb_set_mode(m,at_polygone_ouvert,at_polygone,n,s);
6867       }
6868     }
6869   }
6870 
cb_Triangle(Fl_Widget * m,void *)6871   static void cb_Triangle(Fl_Widget * m , void*) {
6872     cb_set_mode(m,at_segment,at_triangle,3,gettext("Point1,Point2,Point3"));
6873   }
6874 
cb_Carre(Fl_Widget * m,void *)6875   static void cb_Carre(Fl_Widget * m , void*) {
6876     cb_set_mode(m,at_carre,at_carre,2,gettext("Point1,Point2"));
6877   }
6878 
cb_Mediatrice(Fl_Widget * m,void *)6879   static void cb_Mediatrice(Fl_Widget * m , void*) {
6880     cb_set_mode(m,at_segment,at_mediatrice,2,gettext("Point1,Point2"));
6881   }
6882 
cb_Perpendiculaire(Fl_Widget * m,void *)6883   static void cb_Perpendiculaire(Fl_Widget * m , void*) {
6884     cb_set_mode(m,at_segment,at_perpendiculaire,2,gettext("Point,Line"));
6885   }
6886 
cb_Parallele(Fl_Widget * m,void *)6887   static void cb_Parallele(Fl_Widget * m , void*) {
6888     cb_set_mode(m,at_segment,at_parallele,2,gettext("Point,Line"));
6889   }
6890 
cb_Mediane(Fl_Widget * m,void *)6891   static void cb_Mediane(Fl_Widget * m , void*) {
6892     cb_set_mode(m,at_segment,at_mediane,3,gettext("Sommet_angle,Point2,Point3"));
6893   }
6894 
cb_Bissectrice(Fl_Widget * m,void *)6895   static void cb_Bissectrice(Fl_Widget * m , void*) {
6896     cb_set_mode(m,at_segment,at_bissectrice,3,gettext("Sommet_angle,Point2,Point3"));
6897   }
6898 
cb_Quadrilatere(Fl_Widget * m,void *)6899   static void cb_Quadrilatere(Fl_Widget * m , void*) {
6900     cb_set_mode(m,at_polygone_ouvert,at_quadrilatere,4,gettext("Point1,Point2,Point3,Point4"));
6901   }
6902 
cb_Triangle_Equilateral(Fl_Widget * m,void *)6903   static void cb_Triangle_Equilateral(Fl_Widget * m , void*) {
6904     cb_set_mode(m,at_segment,at_triangle_equilateral,(dim3(m)?3:2),(dim3(m)?gettext("Point1,Point2,Point_in_plane"):gettext("Point1,Point2")));
6905   }
6906 
cb_inscrit(Fl_Widget * m,void *)6907   static void cb_inscrit(Fl_Widget * m , void*) {
6908     cb_set_mode(m,at_segment,at_inscrit,3,gettext("Point1,Point2,Point3"));
6909   }
6910 
cb_exinscrit(Fl_Widget * m,void *)6911   static void cb_exinscrit(Fl_Widget * m , void*) {
6912     cb_set_mode(m,at_segment,at_exinscrit,3,gettext("Point1,Point2,Point3"));
6913   }
6914 
cb_circonscrit(Fl_Widget * m,void *)6915   static void cb_circonscrit(Fl_Widget * m , void*) {
6916     cb_set_mode(m,at_segment,at_circonscrit,3,gettext("Point1,Point2,Point3"));
6917   }
6918 
cb_ellipse(Fl_Widget * m,void *)6919   static void cb_ellipse(Fl_Widget * m , void*) {
6920     cb_set_mode(m,at_segment,at_ellipse,3,gettext("Focus1,Focus2,Point_on_ellipse"));
6921   }
6922 
cb_parabole(Fl_Widget * m,void *)6923   static void cb_parabole(Fl_Widget * m , void*) {
6924     cb_set_mode(m,at_segment,at_parabole,2,gettext("Focus,Point_or_line"));
6925   }
6926 
cb_hyperbole(Fl_Widget * m,void *)6927   static void cb_hyperbole(Fl_Widget * m , void*) {
6928     cb_set_mode(m,at_segment,at_hyperbole,3,gettext("Focus1,Focus2,Point_on_hyperbola"));
6929   }
6930 
cb_plan(Fl_Widget * m,void *)6931   static void cb_plan(Fl_Widget * m , void*) {
6932     cb_set_mode(m,at_segment,at_plan,3,gettext("Point1,Point2,Point3"));
6933   }
6934 
cb_sphere(Fl_Widget * m,void *)6935   static void cb_sphere(Fl_Widget * m , void*) {
6936     cb_set_mode(m,at_sphere,at_sphere,2,gettext("Center,Point_on_sphere"));
6937   }
6938 
6939   Fl_Menu_Item Figure_menu[] = {
6940     {gettext("Fig"), 0,  0, 0, 64, 0, 0, 14, 56},
6941     {gettext("Save figure as text"), 0,  (Fl_Callback*)cb_Figure_Save, 0, 0, 0, 0, 14, 56},
6942     {gettext("Save as alternate filename"), 0,  (Fl_Callback*)cb_Figure_Save_as, 0, 0, 0, 0, 14, 56},
6943     {gettext("Insert"), 0,  (Fl_Callback*)cb_Figure_Insert, 0, 0, 0, 0, 14, 56},
6944     {gettext("Export Print"), 0,  0, 0, 64, 0, 0, 14, 56},
6945     {gettext("EPS PNG and preview"), 0,  (Fl_Callback*)cb_Figure_Preview, 0, 0, 0, 0, 14, 56},
6946     {gettext("To printer"), 0,  (Fl_Callback*)cb_Figure_Print, 0, 0, 0, 0, 14, 56},
6947     {gettext("Latex preview"), 0,  (Fl_Callback*)cb_Figure_LaTeX_Preview, 0, 0, 0, 0, 14, 56},
6948     {gettext("Latex printer"), 0,  (Fl_Callback*)cb_Figure_LaTeX_Print, 0, 0, 0, 0, 14, 56},
6949     {0}, // end print
6950     {0}, // end file
6951     {gettext("Edit"), 0,  0, 0, 64, 0, 0, 14, 56},
6952     {gettext("Add parameter"), 0,  (Fl_Callback *) cb_Figure_Parameter, 0, 0, 0, 0, 14, 56},
6953     {gettext("Add numerical value"), 0,  (Fl_Callback *) cb_NumericalEdit, 0, 0, 0, 0, 14, 56},
6954     {gettext("Add new entry"), 0x8006e,  (Fl_Callback *) cb_New_Input, 0, 0, 0, 0, 14, 56},
6955     {gettext("Add an object trace"), 0,  (Fl_Callback *) cb_Graph_Traceobject, 0, 0, 0, 0, 14, 56},
6956     {gettext("Change selection attribut"), 0,  (Fl_Callback *) cb_Figure_Change_Attributs, 0, 0, 0, 0, 14, 56},
6957     {gettext("Paste"), 0,  (Fl_Callback *) cb_Paste, 0, 0, 0, 0, 14, 56},
6958     {gettext("Delete selected levels"), 0,  (Fl_Callback *) cb_Delete, 0, 0, 0, 0, 14, 56},
6959     {gettext("Portrait"), 0,  (Fl_Callback *) cb_Figure_Portrait, 0, 0, 0, 0, 14, 56},
6960     {gettext("Landscape"), 0,  (Fl_Callback *) cb_Figure_Landscape, 0, 0, 0, 0, 14, 56},
6961     {gettext("Undo"), 0x4007a,  (Fl_Callback *) History_cb_Undo, 0, 0, 0, 0, 14, 56},
6962     {gettext("Redo"), 0x40079,  (Fl_Callback *) History_cb_Redo, 0, 0, 0, 0, 14, 56},
6963     {gettext("Focus"), 0x8006d,  (Fl_Callback *) cb_Figure_Focus, 0, 0, 0, 0, 14, 56},
6964     {0}, // end Edit
6965     {gettext("Graph"), 0,  0, 0, 64, 0, 0, 14, 56},
6966     {gettext("Function"), 0,  (Fl_Callback *) cb_Figure_Function, 0, 0, 0, 0, 14, 56},
6967     {gettext("Tangent"), 0,  (Fl_Callback *) cb_Figure_Tangent, 0, 0, 0, 0, 14, 56},
6968     {gettext("Recurrent sequence (2-d)"), 0,  (Fl_Callback *) cb_Figure_Sequence, 0, 0, 0, 0, 14, 56},
6969     {gettext("Area under curve"), 0,  (Fl_Callback *) cb_Figure_Plotarea, 0, 0, 0, 0, 14, 56},
6970     {gettext("Parametric"), 0,  (Fl_Callback *) cb_Figure_Param, 0, 0, 0, 0, 14, 56},
6971     {gettext("Polar (2-d)"), 0,  (Fl_Callback *) cb_Figure_Polar, 0, 0, 0, 0, 14, 56},
6972     {gettext("Implicit"), 0,  (Fl_Callback *) cb_Figure_Implicit, 0, 0, 0, 0, 14, 56},
6973     {gettext("Slopefield Ode (2-d)"), 0,  (Fl_Callback *) cb_Figure_Plotfield, 0, 0, 0, 0, 14, 56},
6974     {0}, // end Math
6975     {0}, // end menu
6976   };
6977 
6978   Fl_Menu_Item Figure_menubut[] = {
6979     {gettext("Frame"), 0,  (Fl_Callback *) cb_Frame, 0, 0, 0, 0, 14, 56},
6980     {gettext("Pointer"), 0,  (Fl_Callback *) cb_Pointer, 0, 0, 0, 0, 14, 56},
6981     {gettext("point"), 0,  (Fl_Callback *) cb_Point, 0, 0, 0, 0, 14, 56},
6982     {gettext("Lines"), 0,  0, 0, 64, 0, 0, 14, 56},
6983     {gettext("segment"), 0,  (Fl_Callback *) cb_Segment, 0, 0, 0, 0, 14, 56},
6984     {gettext("vector"), 0,  (Fl_Callback *) cb_Vector, 0, 0, 0, 0, 14, 56},
6985     {gettext("half_line"), 0,  (Fl_Callback *) cb_Demi_Droite, 0, 0, 0, 0, 14, 56},
6986     {gettext("line"), 0,  (Fl_Callback *) cb_Droite, 0, 0, 0, 0, 14, 56},
6987     {gettext("parallel"), 0,  (Fl_Callback *) cb_Parallele, 0, 0, 0, 0, 14, 56},
6988     {gettext("perpendicular"), 0,  (Fl_Callback *) cb_Perpendiculaire, 0, 0, 0, 0, 14, 56},
6989     {gettext("perpen_bisector"), 0,  (Fl_Callback *) cb_Mediatrice, 0, 0, 0, 0, 14, 56},
6990     {gettext("median_line"), 0,  (Fl_Callback *) cb_Mediane, 0, 0, 0, 0, 14, 56},
6991     {gettext("bisector"), 0,  (Fl_Callback *) cb_Bissectrice, 0, 0, 0, 0, 14, 56},
6992     {0}, // end Lines
6993     {gettext("Polygons"), 0,  0, 0, 64, 0, 0, 14, 56},
6994     {gettext("triangle"), 0,  (Fl_Callback *) cb_Triangle, 0, 0, 0, 0, 14, 56},
6995     {gettext("equilateral_triangle"), 0,  (Fl_Callback *) cb_Triangle_Equilateral, 0, 0, 0, 0, 14, 56},
6996     {gettext("square"), 0,  (Fl_Callback *) cb_Carre, 0, 0, 0, 0, 14, 56},
6997     {gettext("quadrilateral"), 0,  (Fl_Callback *) cb_Quadrilatere, 0, 0, 0, 0, 14, 56},
6998     {gettext("polygon"), 0,  (Fl_Callback *) cb_Polygone, 0, 0, 0, 0, 14, 56},
6999     {0}, // end Triangle
7000     {gettext("Circles"), 0,  0, 0, 64, 0, 0, 14, 56},
7001     {gettext("circle"), 0,  (Fl_Callback *) cb_Circle, 0, 0, 0, 0, 14, 56},
7002     {gettext("incircle"), 0,  (Fl_Callback *) cb_inscrit, 0, 0, 0, 0, 14, 56},
7003     {gettext("excircle"), 0,  (Fl_Callback *) cb_exinscrit, 0, 0, 0, 0, 14, 56},
7004     {gettext("circumcircle"), 0,  (Fl_Callback *) cb_circonscrit, 0, 0, 0, 0, 14, 56},
7005     {0}, // end Circles
7006     {gettext("Curves"), 0,  0, 0, 64, 0, 0, 14, 56},
7007     {gettext("ellipse"), 0,  (Fl_Callback *) cb_ellipse, 0, 0, 0, 0, 14, 56},
7008     {gettext("hyperbola"), 0,  (Fl_Callback *) cb_hyperbole, 0, 0, 0, 0, 14, 56},
7009     {gettext("parabola"), 0,  (Fl_Callback *) cb_parabole, 0, 0, 0, 0, 14, 56},
7010     {gettext("plotode"), 0,  (Fl_Callback *) cb_plotode, 0, 0, 0, 0, 14, 56},
7011     {0}, // end Conics
7012     {gettext("Surfaces (3d)"), 0,  0, 0, 64, 0, 0, 14, 56},
7013     {gettext("plane"), 0,  (Fl_Callback *) cb_plan, 0, 0, 0, 0, 14, 56},
7014     {gettext("sphere"), 0,  (Fl_Callback *) cb_sphere, 0, 0, 0, 0, 14, 56},
7015     {0}, // end Surfaces
7016     {gettext("Measures"), 0,  0, 0, 64, 0, 0, 14, 56},
7017     {gettext("distanceat"), 0,  (Fl_Callback *) cb_DistanceAB, 0, 0, 0, 0, 14, 56},
7018     {gettext("angleat"), 0,  (Fl_Callback *) cb_AngleABC, 0, 0, 0, 0, 14, 56},
7019     {gettext("areaat"), 0,  (Fl_Callback *) cb_Area, 0, 0, 0, 0, 14, 56},
7020     {gettext("perimeterat"), 0,  (Fl_Callback *) cb_Perimeter, 0, 0, 0, 0, 14, 56},
7021     {gettext("slopeat"), 0,  (Fl_Callback *) cb_Slope, 0, 0, 0, 0, 14, 56},
7022     {gettext("distanceatraw"), 0,  (Fl_Callback *) cb_DistanceABraw, 0, 0, 0, 0, 14, 56},
7023     {gettext("angleatraw"), 0,  (Fl_Callback *) cb_AngleABCraw, 0, 0, 0, 0, 14, 56},
7024     {gettext("areaatraw"), 0,  (Fl_Callback *) cb_Arearaw, 0, 0, 0, 0, 14, 56},
7025     {gettext("perimeteratraw"), 0,  (Fl_Callback *) cb_Perimeterraw, 0, 0, 0, 0, 14, 56},
7026     {gettext("slopeatraw"), 0,  (Fl_Callback *) cb_Sloperaw, 0, 0, 0, 0, 14, 56},
7027     {0}, // end measures
7028     {gettext("Transformations"), 0,  0, 0, 64, 0, 0, 14, 56},
7029     {gettext("reflection"), 0,  (Fl_Callback *) cb_Symetrie, 0, 0, 0, 0, 14, 56},
7030     {gettext("rotation"), 0,  (Fl_Callback *) cb_Rotation, 0, 0, 0, 0, 14, 56},
7031     {gettext("translation"), 0,  (Fl_Callback *) cb_Translation, 0, 0, 0, 0, 14, 56},
7032     {gettext("projection"), 0,  (Fl_Callback *) cb_Projection, 0, 0, 0, 0, 14, 56},
7033     {gettext("homothety"), 0,  (Fl_Callback *) cb_Homothetie, 0, 0, 0, 0, 14, 56},
7034     {gettext("similarity"), 0,  (Fl_Callback *) cb_Similitude, 0, 0, 0, 0, 14, 56},
7035     {gettext("inversion"), 0,  (Fl_Callback *) cb_Inversion, 0, 0, 0, 0, 14, 56},
7036     {gettext("reciprocation"), 0,  (Fl_Callback *) cb_Reciprocation, 0, 0, 0, 0, 14, 56},
7037     {0}, // end transformations
7038     {gettext("Intersections"), 0,  0, 0, 64, 0, 0, 14, 56},
7039     {gettext("inter_unique (1 point)"), 0,  (Fl_Callback *) cb_Inter_Unique, 0, 0, 0, 0, 14, 56},
7040     {gettext("inter (close to a point)"), 0,  (Fl_Callback *) cb_Inter_3, 0, 0, 0, 0, 14, 56},
7041     {gettext("inter (list of points)"), 0,  (Fl_Callback *) cb_Inter, 0, 0, 0, 0, 14, 56},
7042     {0}, // end intersections
7043     {gettext("tangent"), 0,  (Fl_Callback *) cb_Tangent, 0, 0, 0, 0, 14, 56},
7044     // {gettext("Exact"), 0,  (Fl_Callback *) cb_Exact, 0, 0, 0, 0, 14, 56},
7045     // {gettext("Approx"), 0,  (Fl_Callback *) cb_Approx, 0, 0, 0, 0, 14, 56},
7046     {0}, // end Menu
7047   };
7048 
7049   // Create a tile with 1st element = a History_Pack, 2nd element geometry
7050   // Pressing enter in a History_Pack Multiline_input should
7051   // eval it + eval below + update parameters and geometry
7052   // by reading Gen_Output values below current level
Figure(int X,int Y,int W,int H,int L,bool dim3)7053   Figure::Figure(int X,int Y,int W,int H,int L,bool dim3):Fl_Tile(X,Y,W,H),namestr(0){
7054     BorderBox * borderbox = new BorderBox(X,Y,w()-labelsize(),h()-labelsize());
7055     resizable(borderbox);
7056     Fl_Tile::end();
7057 #ifdef IPAQ
7058     disposition=1;
7059     if (H<340)
7060       H=340;
7061 #else
7062     disposition=0;
7063 #endif
7064     box(FL_FLAT_BOX);
7065     if (L>H/2)
7066       L=H/2;
7067     labelsize(L);
7068     int l=L+6;
7069     Fl_Group::current(this);
7070     if (disposition==1)
7071       s = new xcas::HScroll (X,Y+l+H/2,W,H/2-l);
7072     else
7073       s = new xcas::HScroll (X,Y+l,W/3,H-l);
7074     s->type(Fl_Scroll::VERTICAL_ALWAYS);
7075     s->box(FL_FLAT_BOX);
7076     History_Pack * hp = new History_Pack (s->x(),s->y(),max(s->w()-2*L,20),max(s->h()-L,20));
7077     // hp->new_question=new_question_multiline_input;
7078     if (hp){
7079       hp->eval_below=true;
7080       hp->eval_below_once=false;
7081     }
7082     hp->labelsize(L);
7083     hp->pretty_output=false;
7084     hp->eval_below=true;
7085     hp->eval=xcas::Xcas_eval;
7086     hp->_insert=xcas::Xcas_pack_insert;
7087     hp->_select=xcas::Xcas_pack_select;
7088     hp->end();
7089     hp->add_entry(-1);
7090     s->end();
7091     win=0;
7092     if (dim3){
7093 #ifdef GRAPH_WINDOW
7094       Fl_Group::current(this);
7095       if (disposition==1){
7096 	win = new Fl_Window(X,Y+l,W,H/2);
7097 	geo = new Geo3d(0,0,W,H/2,hp);
7098 	win->end();
7099       }
7100       else {
7101 	win = new Fl_Window(X+W/3,Y+l,2*W/3,H-l);
7102 	geo = new Geo3d(0,0,2*W/3,H-l,hp);
7103 	Fl_Group::current(win);
7104 	win->end();
7105       }
7106       // Problem: win is not in the window hierarchy, can not call win->show()
7107       Fl_Group::current(this);
7108 #else
7109       if (disposition==1)
7110 	geo = new Geo3d(X,Y+l,W,H/2,hp);
7111       else
7112 	geo = new Geo3d(X+W/3,Y+l,2*W/3,H-l,hp);
7113 #endif
7114     }
7115     else {
7116       if (disposition==1)
7117 	geo = new Geo2d(X,Y+l,W,H/2,hp);
7118       else
7119 	geo = new Geo2d(X+W/3,Y+l,2*W/3,H-l,hp);
7120     }
7121     geo->labelsize(L);
7122     geo->autoscale();
7123     geo->orthonormalize();
7124     hp->focus(0,true); //geo->handle(FL_FOCUS);
7125     barre=new Fl_Group(X,Y,W,l);
7126     Fl_Menu_Bar * menubar = new Fl_Menu_Bar(X,Y,Max(W/4,68),l);
7127     int n= Figure_menu->size();
7128     Fl_Menu_Item * menuitem = new Fl_Menu_Item[n];
7129     for (int i=0;i<n;++i)
7130       *(menuitem+i)=*(Figure_menu+i);
7131     menubar->menu (menuitem);
7132     change_menu_fontsize(menuitem,2,L); // 2=#submenus
7133     int x=X;
7134     x += menubar->w();
7135     mode = new Fl_Output(x,Y,Max((7*W)/60,35),l);
7136     x += mode->w();
7137     mode->value(gettext("Frame"));
7138     Fl_Menu_Button * menubut = new Fl_Menu_Button(x,Y,(4*W)/60,l);
7139     menubut->tooltip(gettext("Set mode for mouse constructions"));
7140 #ifndef IPAQ
7141     menubut->label("Mode");
7142 #endif
7143     n = Figure_menubut->size();
7144     Fl_Menu_Item * menuitembut = new Fl_Menu_Item[n];
7145     for (int i=0;i<n;++i)
7146       *(menuitembut+i)=*(Figure_menubut+i);
7147     menubut->menu (menuitembut);
7148     change_menu_fontsize(menuitembut,2,L); // 2=#submenus
7149     x += menubut->w();
7150     couleur = new Fl_Button(x,Y,(3*l)/2,l);
7151     x += couleur->w();
7152     couleur->color(0);
7153     couleur->tooltip(gettext("Color used for next mouse drawings"));
7154     couleur->callback((Fl_Callback *) cb_Figure_Color);
7155     lt = new Line_Type(x,Y,l,l);
7156     lt->show_pnt(true);
7157     lt->show_text(true);
7158     lt->show_poly(true);
7159     lt->tooltip(gettext("Line style used for next mouse drawings"));
7160     lt->callback((Fl_Callback *) cb_Figure_Line_Type);
7161     x += l;
7162     Fl_Check_Button * checkb = new Fl_Check_Button(x,Y,3*l,l,"Step");
7163     checkb->value(false);
7164     checkb->tooltip(gettext("Check for step evaluation"));
7165     checkb->callback((Fl_Callback *) cb_Figure_Autoeval);
7166     x += checkb->w();
7167     checkdisp = new Fl_Check_Button(x,Y,6*l,l,"Landscape");
7168     checkdisp->value(false);
7169     checkdisp->tooltip(gettext("Check for landscape"));
7170     checkdisp->callback((Fl_Callback *) cb_Figure_Disposition);
7171     x += checkdisp->w();
7172     Fl_Check_Button * checkex = new Fl_Check_Button(x,Y,l,l,"~");
7173     checkex->value(true);
7174     checkex->tooltip(gettext("Check if mouse clicks in approx mode"));
7175     checkex->callback((Fl_Callback *) cb_Figure_Approx);
7176     x += checkex->w();
7177     name = new Fl_Button(x,Y,W+X-x,l,"<Save figure as text>");
7178     name->callback((Fl_Callback *) cb_Figure_Save);
7179     name->tooltip(gettext("Save current figure commands independently of the session"));
7180     name->labelsize(L);
7181     name->hide();
7182     barre->end();
7183     parent_redraw(this);
7184   }
7185 
handle(int event)7186   int BorderBox::handle(int event){
7187     return 0;
7188   }
7189 
draw()7190   void Figure::draw(){
7191     if (win && !win->shown())
7192       win->show();
7193     Fl_Tile::draw();
7194   }
7195 
resize(int X,int Y,int W,int H,double dhp,double dgeo,double dmp)7196   void Figure::resize(int X,int Y,int W,int H,double dhp,double dgeo,double dmp){
7197     Fl_Widget::resize(X,Y,W,H);
7198     double dall=dhp+dgeo+dmp;
7199     dhp /= dall; dgeo /= dall; dmp /= dall;
7200     int l=labelsize()+6;
7201     if (W>10*l && dmp*W<4*l){
7202       dmp=4.0/W*l;
7203       dhp=dhp/(dhp+dgeo);
7204       dgeo=1.0-dhp-dmp;
7205     }
7206     barre->resize(X,Y,W,l);
7207     if (disposition==1){
7208       checkdisp->value(true);
7209       double dgeomp=dgeo+dmp;
7210       geo->resize(X,Y+l,max(W-5*l,int(W*dgeo/dgeomp+.5)),int(H*dgeomp+.5));
7211       geo->mouse_param_group->resize(X+geo->w(),Y+l,W-geo->w(),geo->h());
7212       s->resize(X,geo->y()+geo->h(),W,H-geo->h()-l);
7213     }
7214     else {
7215       checkdisp->value(false);
7216       int sw=s->w(),gw=geo->w(),mw=geo->mouse_param_group->w();
7217       int dw= W-(sw+gw+mw);
7218       sw += dw;
7219       if (sw<l || dhp!=0.25 || dgeo!=0.5 || dmp!=0.25 ){
7220 	sw=int(W*dhp+.5);
7221 	gw=int(W*dgeo+.5);
7222       }
7223       s->resize(X,Y+l,sw,H-l);
7224       geo->resize(X+s->w(),Y+l,gw,H-l);
7225       geo->mouse_param_group->resize(X+s->w()+geo->w(),Y+l,W-gw-sw,H-l);
7226     }
7227     //geo->hp->Fl_Group::resize(s->x(),s->y(),max(s->w()-l,20),max(s->h()-l,20));
7228     init_sizes();
7229     Fl_Group::resize(x(),y(),w(),h());
7230     redraw();
7231   }
7232 
animate(int nframes)7233   vecteur Graph2d3d::animate(int nframes){
7234     int n=param_group->children();
7235     vecteur res;
7236     if (!n || !hp)
7237       return res;
7238     bool back=nframes<0;
7239     if (back)
7240       nframes=-nframes;
7241     if (nframes<2)
7242       nframes=2;
7243     Gen_Value_Slider * last=0;
7244     for (int i=0;i<nframes;++i){
7245       for (int j=n-1;j>=0;--j){
7246 	if (Gen_Value_Slider * gvs = dynamic_cast<Gen_Value_Slider *>(param_group->child(j))){
7247 	  last=gvs;
7248 	  double v=gvs->minimum()+(i*(gvs->maximum()-gvs->minimum()))/(nframes-1);
7249 	  gvs->value(v);
7250 	  gvs->adjust(false);
7251 	}
7252       }
7253       if (!last)
7254 	return res;
7255       last->adjust(true);
7256       // wait for the end of evaluation
7257       for (;;){
7258 	Fl_Widget *o = Fl::readqueue();
7259 	if (Xcas_Cancel && o==Xcas_Cancel){
7260 	  o->do_callback();
7261 	  hp->doing_eval=false;
7262 	  return res;
7263 	}
7264 	Xcas_idle_function(0);
7265 	if (!hp->doing_eval && !is_context_busy(hp->contextptr))
7266 	  break;
7267       }
7268       Fl::flush();
7269       vecteur resi;
7270       const_iterateur it=plot_instructions.begin(),itend=plot_instructions.end();
7271       for (;it!=itend;++it){
7272 	gen tmp = *it;
7273 	if (tmp.is_symb_of_sommet(at_parameter))
7274 	  continue;
7275 	if (tmp.is_symb_of_sommet(at_pnt) && tmp._SYMBptr->feuille.type==_VECT){
7276 	  vecteur attributs=*tmp._SYMBptr->feuille._VECTptr;
7277 	  tmp=evalf(attributs[0],eval_level(hp->contextptr),hp->contextptr);
7278 	  attributs=vecteur(attributs.begin()+1,attributs.end());
7279 	  tmp=pnt_attrib(tmp,attributs,hp->contextptr);
7280 	}
7281 	else
7282 	  tmp=evalf(tmp,eval_level(hp->contextptr),hp->contextptr);
7283 	resi.push_back(tmp);
7284       }
7285       res.push_back(resi);
7286     }
7287     if (back){
7288       for (int i=nframes-1;i>=0;i--)
7289 	res.push_back(res[i]);
7290     }
7291     return res;
7292   }
7293 
latex_save_figure()7294   std::string Turtle::latex_save_figure(){
7295     static int nsession=0;
7296     nsession++;
7297     double xunit=giac::horiz_latex/w();
7298     double save_vert_latex=giac::vert_latex;
7299     giac::vert_latex=xunit*h();
7300     string thename="tortue"+print_INT_(nsession)+".tex";
7301     char * filename = file_chooser(gettext("Export to LaTeX"),"*.tex",thename.c_str());
7302 
7303     if (filename)
7304       graph2tex(filename,turtlevect2vecteur(*turtleptr),0,w(),0,h(),xunit,xunit,true,get_context(this));
7305     giac::vert_latex=save_vert_latex;
7306     return thename;
7307   }
7308 
7309 
draw()7310   void Turtle::draw(){
7311 #if 0
7312     context * contextptr=get_context(this);
7313     if (is_context_busy(contextptr))
7314       return;
7315 #endif
7316     pthread_mutex_lock(&turtle_mutex);
7317     try {
7318       int clip_x,clip_y,clip_w,clip_h;
7319       fl_clip_box(x(),y(),w(),h(),clip_x,clip_y,clip_w,clip_h);
7320       fl_push_clip(clip_x,clip_y,clip_w,clip_h);
7321       indraw();
7322       fl_pop_clip();
7323     } catch (...){ }
7324     pthread_mutex_unlock(&turtle_mutex);
7325   }
7326 
indraw()7327   void Turtle::indraw(){
7328     int deltax=x(),deltay=y();
7329     int horizontal_pixels=w()-2*giac::COORD_SIZE;
7330     // Check for fast redraw
7331     // Then redraw the background
7332     fl_color(FL_WHITE);
7333     if (!redraw_cap_only)
7334       fl_rectf(deltax, deltay, w(), h());
7335     if (turtleptr && !turtleptr->empty()){
7336       if (turtlezoom>8)
7337 	turtlezoom=8;
7338       if (turtlezoom<0.125)
7339 	turtlezoom=0.125;
7340       // check that position is not out of screen
7341       logo_turtle t=turtleptr->back();
7342       double x=turtlezoom*(t.x-turtlex);
7343       if (x<0)
7344 	turtlex += int(x/turtlezoom);
7345       if (x>=w()-10)
7346 	turtlex += int((x-w()+10)/turtlezoom);
7347       double y=turtlezoom*(t.y-turtley);
7348       if (y<0)
7349 	turtley += int(y/turtlezoom);
7350       if (y>h()-10)
7351 	turtley += int((y-h()+10)/turtlezoom);
7352     }
7353     if (maillage & 0x3){
7354       fl_color(FL_BLACK);
7355       double xdecal=std::floor(turtlex/10.0)*10;
7356       double ydecal=std::floor(turtley/10.0)*10;
7357       if ( (maillage & 0x3)==1){
7358 	for (double i=xdecal;i<w()+xdecal;i+=10){
7359 	  for (double j=ydecal;j<h()+ydecal;j+=10){
7360 	    fl_point(deltax+int((i-turtlex)*turtlezoom+.5),deltay+h()-int((j-turtley)*turtlezoom+.5));
7361 	  }
7362 	}
7363       }
7364       else {
7365 	double dj=std::sqrt(3.0)*10,i0=xdecal;
7366 	for (double j=ydecal;j<h()+ydecal;j+=dj){
7367 	  int J=deltay+int(h()-(j-turtley)*turtlezoom);
7368 	  for (double i=i0;i<w()+xdecal;i+=10){
7369 	    fl_point(deltax+int((i-turtlex)*turtlezoom+.5),J);
7370 	  }
7371 	  i0 += dj;
7372 	  while (i0>=10)
7373 	    i0 -= 10;
7374 	}
7375       }
7376     }
7377     // Show turtle position/cap
7378     if (turtleptr && !turtleptr->empty() && !(maillage & 0x4)){
7379       logo_turtle turtle=turtleptr->back();
7380       fl_color(FL_YELLOW);
7381       fl_rectf(deltax+horizontal_pixels,deltay,w()-horizontal_pixels,2*COORD_SIZE);
7382       fl_color(FL_BLACK);
7383       fl_rect(deltax, deltay, w(), h());
7384       fl_font(FL_HELVETICA,labelsize());
7385       fl_draw(("x "+print_INT_(int(turtle.x+.5))).c_str(),deltax+horizontal_pixels,deltay+(2*COORD_SIZE)/3-2);
7386       fl_draw(("y "+print_INT_(int(turtle.y+.5))).c_str(),deltax+horizontal_pixels,deltay+(4*COORD_SIZE)/3-3);
7387       fl_draw(("t "+print_INT_(int(turtle.theta+.5))).c_str(),deltax+horizontal_pixels,deltay+2*COORD_SIZE-4);
7388     }
7389     if (redraw_cap_only){
7390       redraw_cap_only=false;
7391       return;
7392     }
7393     // draw turtle Logo
7394     if (turtleptr){
7395       int l=turtleptr->size();
7396       if (l>0){
7397 	logo_turtle prec =(*turtleptr)[0];
7398 	for (int k=1;k<l;++k){
7399 	  logo_turtle current =(*turtleptr)[k];
7400 	  if (!current.s.empty()){ // Write a string
7401 	    fl_font(FL_HELVETICA,current.radius);
7402 	    xcas_color(current.color);
7403 	    fl_draw(current.s.c_str(),int(deltax+turtlezoom*(current.x-turtlex)),int(deltay+h()-turtlezoom*(current.y-turtley)));
7404 	  }
7405 	  else {
7406 	    if (current.radius>0){
7407 	      int r=current.radius & 0x1ff; // bit 0-8
7408 	      double theta1,theta2;
7409 	      if (current.direct){
7410 		theta1=prec.theta+double((current.radius >> 9) & 0x1ff); // bit 9-17
7411 		theta2=prec.theta+double((current.radius >> 18) & 0x1ff); // bit 18-26
7412 	      }
7413 	      else {
7414 		theta1=prec.theta-double((current.radius >> 9) & 0x1ff); // bit 9-17
7415 		theta2=prec.theta-double((current.radius >> 18) & 0x1ff); // bit 18-26
7416 	      }
7417 	      bool rempli=(current.radius >> 27) & 0x1;
7418 	      bool seg=(current.radius >> 28) & 0x1; // not yet supported
7419 	      double angle;
7420 	      int x,y,R;
7421 	      R=int(2*turtlezoom*r+.5);
7422 	      angle = M_PI/180*(theta2-90);
7423 	      if (current.direct){
7424 		x=int(turtlezoom*(current.x-turtlex-r*std::cos(angle) - r)+.5);
7425 		y=int(turtlezoom*(current.y-turtley-r*std::sin(angle) + r)+.5);
7426 	      }
7427 	      else {
7428 		x=int(turtlezoom*(current.x-turtlex+r*std::cos(angle) -r)+.5);
7429 		y=int(turtlezoom*(current.y-turtley+r*std::sin(angle) +r)+.5);
7430 	      }
7431 	      xcas_color(current.color);
7432 	      if (current.direct){
7433 		if (rempli)
7434 		  fl_pie_seg(deltax+x,deltay+h()-y,R,R,theta1-90,theta2-90,seg);
7435 		else
7436 		  fl_arc(deltax+x,deltay+h()-y,R,R,theta1-90,theta2-90);
7437 	      }
7438 	      else {
7439 		if (rempli)
7440 		  fl_pie_seg(deltax+x,deltay+h()-y,R,R,90+theta2,90+theta1,seg);
7441 		else
7442 		  fl_arc(deltax+x,deltay+h()-y,R,R,90+theta2,90+theta1);
7443 	      }
7444 	    } // end radius>0
7445 	    else {
7446 	      if (prec.mark){
7447 		xcas_color(prec.color);
7448 		fl_line(deltax+int(turtlezoom*(prec.x-turtlex)+.5),deltay+int(h()+turtlezoom*(turtley-prec.y)+.5),deltax+int(turtlezoom*(current.x-turtlex)+.5),deltay+int(h()+turtlezoom*(turtley-current.y)+.5));
7449 	      }
7450 	    }
7451 	    if (current.radius<-1 && k+current.radius>=0){
7452 	      // poly-line from (*turtleptr)[k+current.radius] to (*turtleptr)[k]
7453 	      fl_begin_complex_polygon();
7454 	      for (int i=0;i>=current.radius;--i){
7455 		logo_turtle & t=(*turtleptr)[k+i];
7456 		fl_vertex(deltax+turtlezoom*(t.x-turtlex),deltay+h()+turtlezoom*(turtley-t.y));
7457 	      }
7458 	      fl_vertex(deltax+turtlezoom*(current.x-turtlex),deltay+h()+turtlezoom*(turtley-current.y));
7459 	      fl_end_complex_polygon();
7460 	    }
7461 	  } // end else (non-string turtle record)
7462 	  prec=current;
7463 	} // end for (all turtle records)
7464 	logo_turtle & t = (*turtleptr)[l-1];
7465 	int x=int(turtlezoom*(t.x-turtlex)+.5);
7466 	int y=int(turtlezoom*(t.y-turtley)+.5);
7467 	double cost=std::cos(t.theta*deg2rad_d);
7468 	double sint=std::sin(t.theta*deg2rad_d);
7469 	int Dx=int(turtlezoom*t.turtle_length*cost/2+.5);
7470 	int Dy=int(turtlezoom*t.turtle_length*sint/2+.5);
7471 	xcas_color(t.color);
7472 	if (t.visible){
7473 	  fl_line(deltax+x+Dy,deltay+h()-(y-Dx),deltax+x-Dy,deltay+h()-(y+Dx));
7474 	  if (!t.mark)
7475 	    xcas_color(t.color+1);
7476 	  fl_line(deltax+x+Dy,deltay+h()-(y-Dx),deltax+x+3*Dx,deltay+h()-(y+3*Dy));
7477 	  fl_line(deltax+x-Dy,deltay+h()-(y+Dx),deltax+x+3*Dx,deltay+h()-(y+3*Dy));
7478 	}
7479       }
7480       return;
7481     } // End logo mode
7482   }
7483 
handle(int event)7484   int Turtle::handle(int event){
7485 #if 0
7486     context * contextptr=get_context(this);
7487     if (is_context_busy(contextptr))
7488       return 0;
7489 #endif
7490     // cerr << event << '\n';
7491     if ( (event==FL_ENTER) || (event==FL_LEAVE) ){
7492       if (event==FL_LEAVE)
7493 	redraw_cap_only=true;
7494       redraw();
7495       return 1;
7496     }
7497     if (event==FL_FOCUS){
7498       Fl::focus(this);
7499       return 1;
7500     }
7501     if (event==FL_PUSH){
7502       push_x=Fl::event_x()-x();
7503       push_y=Fl::event_y()-y();
7504       Fl::focus(this);
7505       return 1;
7506     }
7507     int current_x=Fl::event_x()-x(),current_y=Fl::event_y()-y();
7508     // int horizontal_pixels=w();
7509     if (event== FL_MOUSEWHEEL ){
7510       if (Fl::e_dy<0)
7511 	turtlezoom *= 0.707 ;
7512       else
7513 	turtlezoom *= 1.414 ;
7514       redraw();
7515       return 1;
7516     }
7517     if (event==FL_RELEASE || event==FL_DRAG){
7518       if (current_y!=push_y){
7519 	turtley += int((current_y-push_y));
7520 	redraw();
7521       }
7522       if (current_x!=push_x){
7523 	turtlex += int((push_x-current_x));
7524 	redraw();
7525       }
7526       push_y=current_y;
7527       push_x=current_x;
7528       return 1;
7529     }
7530     if (event==FL_KEYBOARD){
7531       switch (Fl::event_key()){
7532       case FL_Left:
7533 	turtlex += 10;
7534 	redraw();
7535 	return 1;
7536       case FL_Up:
7537 	turtley -= 10;
7538 	redraw();
7539 	return 1;
7540       case FL_Right:
7541 	turtlex -= 10;
7542 	redraw();
7543 	return 1;
7544       case FL_Down:
7545 	turtley += 10;
7546 	redraw();
7547 	return 1;
7548       case '+':
7549 	turtlezoom *= 1.414 ;
7550 	redraw();
7551 	return 1;
7552       case '-':
7553 	turtlezoom *= 0.707 ;
7554 	redraw();
7555 	return 1;
7556       }
7557     }
7558     return 0;
7559   }
7560 
~Turtle()7561   Turtle::~Turtle(){
7562     context * contextptr=get_context(this);
7563     if (turtle(contextptr).widget==this)
7564       turtle(contextptr).widget=0;
7565   }
7566 
cb_Logo_button(No_Focus_Button * b,void *)7567   void cb_Logo_button(No_Focus_Button * b,void *){
7568     if (!Fl::focus())
7569       return;
7570     context * contextptr=get_context(b);
7571     int l=language(contextptr);
7572     string text;
7573     if (b->label()==gettext("fw"))
7574       text=localize("avance ",l);
7575     if (b->label()==gettext("bw"))
7576       text=localize("recule ",l);
7577     if (b->label()==gettext("tr"))
7578       text=localize("tourne_droite ",l);
7579     if (b->label()==gettext("tl"))
7580       text=localize("tourne_gauche ",l);
7581     if (b->label()==gettext("ss"))
7582       text=localize("pas_de_cote ",l);
7583     if (b->label()==gettext("ju"))
7584       text=localize("saute ",l);
7585     if (b->label()==gettext("pe")){
7586       context * contextptr=get_context(b);
7587       text=localize("crayon ",l);
7588       int col = turtle(contextptr).color;
7589       col=fl_show_colormap((Fl_Color) col);
7590       string s=col<1000?print_INT_(col):"";
7591       text += s;
7592       // b->color(col);
7593     }
7594     if (b->label()==gettext("ci"))
7595       text=localize("rond ",l);
7596     if (b->label()==gettext("di"))
7597       text=localize("disque ",l);
7598     if (b->label()==gettext("fr"))
7599       text=localize("rectangle_plein ",l);
7600     if (b->label()==gettext("ft"))
7601       text=localize("triangle_plein ",l);
7602     if (b->label()==gettext("cl"))
7603       text=localize("efface ",l);
7604     if (b->label()==gettext("ec"))
7605       text=localize("ecris ",l);
7606     if (b->label()==gettext("sg"))
7607       text=localize("signe ",l);
7608     if (Fl_Text_Editor * ed=dynamic_cast<Fl_Text_Editor *>(Xcas_input_focus)){
7609       int i=ed->insert_position();
7610       ed->buffer()->insert(i,text.c_str());
7611       ed->insert_position(i+text.size());
7612       return;
7613     }
7614     Fl::focus(Xcas_input_focus);
7615     if (!text.empty())
7616       help_output(text.substr(0,text.size()-1),language(get_context(Fl::focus())));
7617 #ifdef __APPLE__
7618     const char * ch=text.c_str();
7619     int ll=strlen(ch);
7620     for (int i=0;i<ll;++ch,++i){
7621       Fl::e_text= (char *) ch;
7622       Fl::e_length=1;
7623       fl_handle(Fl::focus());
7624     }
7625 #else
7626     Fl::e_text= (char *) text.c_str();
7627     Fl::e_length=text.size();
7628     fl_handle(Fl::focus());
7629 #endif
7630   }
7631 
Logo_eval(Fl_Widget * w)7632   Fl_Widget * Logo_eval(Fl_Widget * w) {
7633     // Check if w is inside a pack inside a scroll inside a Logo group
7634     const context * contextptr = get_context(w);
7635     if (Fl_Input * i=dynamic_cast<Fl_Input *>(w)){
7636       Fl_Group * g=parent_skip_scroll(w->parent()); // should be a pack
7637       if (g)
7638 	g=parent_skip_scroll(g);
7639       if (Logo * l= dynamic_cast<Logo *>(g)){
7640 	string s(i->value());
7641 	if (dynamic_cast<Multiline_Input_tab *>(i)){
7642 	  if (!s.empty() && s[s.size()-1]!=';')
7643 	    s += ";\n";
7644 	  else
7645 	    s += '\n';
7646 	  gen g(s,contextptr);
7647 	  if (!giac::first_error_line(contextptr)){
7648 	    l->ed->editor->insert_position(l->ed->editor->buffer()->length());
7649 	    l->ed->editor->insert(s.c_str());
7650 	  }
7651 	  else {
7652 	    string logs(gettext("Not registered\n"));
7653 	    logs += gettext("Parse error line ")+giac::print_INT_(giac::first_error_line(contextptr))+ gettext(" column ")+print_INT_(giac::lexer_column_number(contextptr))+ gettext(" at ") +giac::error_token_name(contextptr);
7654 	    fl_alert("%s",logs.c_str());
7655 	  }
7656 	}
7657 	else
7658 	  s = "// "+s+'\n';
7659 	l->t->redraw();
7660       }
7661     }
7662     if (Xcas_Text_Editor * i=dynamic_cast<Xcas_Text_Editor *>(w)){
7663       Fl_Group * g=parent_skip_scroll(w->parent()); // should be a pack
7664       if (g)
7665 	g=parent_skip_scroll(g);
7666       if (Logo * l= dynamic_cast<Logo *>(g)){
7667 	string s(i->value());
7668 	if (!s.empty() && s[s.size()-1]!=';')
7669 	  s += ";\n";
7670 	else
7671 	  s += '\n';
7672 	gen g(s,contextptr);
7673 	if (!giac::first_error_line(contextptr)){
7674 	  l->ed->editor->insert_position(l->ed->editor->buffer()->length());
7675 	  l->ed->editor->insert(s.c_str());
7676 	}
7677 	else {
7678 	  string logs(gettext("Not registered\n"));
7679 	  logs += gettext("Parse error line ")+giac::print_INT_(giac::first_error_line(contextptr))+ gettext(" column ")+print_INT_(giac::lexer_column_number(contextptr))+ gettext(" at ") +giac::error_token_name(contextptr);
7680 	  fl_alert("%s",logs.c_str());
7681 	}
7682 	l->t->redraw();
7683       }
7684     }
7685     return Xcas_eval(w);
7686   }
7687 
in_find_turtle(Fl_Widget * wid)7688   Turtle * in_find_turtle(Fl_Widget * wid){
7689     if (Turtle * g=dynamic_cast<Turtle *>(wid))
7690       return g;
7691     if (Fl_Group * gr =dynamic_cast<Fl_Group *>(wid)){
7692       // search in children
7693       int n=gr->children();
7694       for (int i=0;i<n;++i){
7695 	if (Turtle * res = in_find_turtle(gr->child(i)))
7696 	  return res;
7697       }
7698     }
7699     return 0;
7700   }
7701 
find_turtle(Fl_Widget * wid)7702   Turtle * find_turtle(Fl_Widget * wid){
7703     if (!wid) return 0;
7704     if (Turtle * res=in_find_turtle(wid))
7705       return res;
7706     return find_turtle(wid->parent());
7707   }
7708 
cb_Logo_Preview(Fl_Menu_ * m,void *)7709   static void cb_Logo_Preview(Fl_Menu_* m , void*) {
7710     Turtle * gr = find_turtle(m);
7711     if (gr)
7712       widget_ps_print(gr,"tortue",true);
7713   }
7714 
cb_Logo_Print(Fl_Menu_ * m,void *)7715   static void cb_Logo_Print(Fl_Menu_* m , void*) {
7716     Turtle * gr = find_turtle(m);
7717     if (gr)
7718       widget_print(gr);
7719   }
7720 
latex(const char * filename_) const7721   const char * Turtle::latex(const char * filename_) const {
7722     const char * filename=0;
7723     if ( (filename=latexfilename(filename_)) ){
7724       double xunit=giac::horiz_latex/w();
7725       double yunit=giac::vert_latex/h();
7726       double unit=xunit<yunit?yunit:xunit;
7727       graph2tex(filename,turtlevect2vecteur(*turtleptr),0,w(),0,h(),unit,unit,true,get_context(this));
7728     }
7729     return filename;
7730   }
7731 
7732 
cb_Logo_LaTeX_Preview(Fl_Menu_ * m,void *)7733   static void cb_Logo_LaTeX_Preview(Fl_Menu_* m , void*) {
7734     Turtle * f=find_turtle(m);
7735     if (f){
7736       string name=f->latex_save_figure();
7737       xdvi(name);
7738     }
7739   }
7740 
cb_Logo_LaTeX_Print(Fl_Menu_ * m,void *)7741   static void cb_Logo_LaTeX_Print(Fl_Menu_* m , void*) {
7742     Turtle * f=find_turtle(m);
7743     if (f){
7744       string name=f->latex_save_figure();
7745       dvips(name);
7746     }
7747   }
7748 
cb_Logo_None(Fl_Menu_ * m,void *)7749   static void cb_Logo_None(Fl_Menu_* m , void*) {
7750     Turtle * f=find_turtle(m);
7751     if (f) { f->maillage=f->maillage & 0x4; f->redraw(); }
7752   }
7753 
cb_Logo_Square(Fl_Menu_ * m,void *)7754   static void cb_Logo_Square(Fl_Menu_* m , void*) {
7755     Turtle * f=find_turtle(m);
7756     if (f) { f->maillage=1 | (f->maillage & 0x4); f->redraw(); }
7757   }
7758 
cb_Logo_Triangle(Fl_Menu_ * m,void *)7759   static void cb_Logo_Triangle(Fl_Menu_* m , void*) {
7760     Turtle * f=find_turtle(m);
7761     if (f) { f->maillage = 2 | (f->maillage & 0x4); f->redraw(); }
7762   }
7763 
cb_Logo_ShowPosition(Fl_Menu_ * m,void *)7764   static void cb_Logo_ShowPosition(Fl_Menu_* m , void*) {
7765     Turtle * f=find_turtle(m);
7766     if (f) { f->maillage=f->maillage & 0x3; f->redraw(); }
7767   }
7768 
cb_Logo_HidePosition(Fl_Menu_ * m,void *)7769   static void cb_Logo_HidePosition(Fl_Menu_* m , void*) {
7770     Turtle * f=find_turtle(m);
7771     if (f) { f->maillage=f->maillage | 0x4; f->redraw(); }
7772   }
7773 
cb_Logo_Color(Fl_Menu_ * m,void *)7774   static void cb_Logo_Color(Fl_Menu_* m , void*) {
7775     const giac::context * contextptr=get_context(m);
7776     int i=fl_show_colormap(Fl_Color(turtle(contextptr).color));
7777     string s="crayon "+print_INT_(i);
7778     if (Fl_Input * i=dynamic_cast<Fl_Input *>(Fl::focus()))
7779       i->insert(s.c_str());
7780     else
7781       fl_message("%s",s.c_str());
7782   }
7783 
cb_Logo_Zoomin(Fl_Menu_ * m,void *)7784   static void cb_Logo_Zoomin(Fl_Menu_* m , void*) {
7785     Turtle * gr = find_turtle(m);
7786     if (gr){
7787       gr->turtlezoom*=1.414;
7788       gr->redraw();
7789     }
7790   }
7791 
cb_Logo_Zoomout(Fl_Menu_ * m,void *)7792   static void cb_Logo_Zoomout(Fl_Menu_* m , void*) {
7793     Turtle * gr = find_turtle(m);
7794     if (gr){
7795       gr->turtlezoom*=0.707;
7796       gr->redraw();
7797     }
7798   }
7799 
cb_Logo_Right(Fl_Menu_ * m,void *)7800   static void cb_Logo_Right(Fl_Menu_* m , void*) {
7801     Turtle * gr = find_turtle(m);
7802     if (gr){
7803       gr->turtlex -= 10 ;
7804       gr->redraw();
7805     }
7806   }
7807 
cb_Logo_Left(Fl_Menu_ * m,void *)7808   static void cb_Logo_Left(Fl_Menu_* m , void*) {
7809     Turtle * gr = find_turtle(m);
7810     if (gr){
7811       gr->turtlex += 10 ;
7812       gr->redraw();
7813     }
7814   }
7815 
cb_Logo_Up(Fl_Menu_ * m,void *)7816   static void cb_Logo_Up(Fl_Menu_* m , void*) {
7817     Turtle * gr = find_turtle(m);
7818     if (gr){
7819       gr->turtley -= 10 ;
7820       gr->redraw();
7821     }
7822   }
7823 
cb_Logo_Down(Fl_Menu_ * m,void *)7824   static void cb_Logo_Down(Fl_Menu_* m , void*) {
7825     Turtle * gr = find_turtle(m);
7826     if (gr){
7827       gr->turtley += 10 ;
7828       gr->redraw();
7829     }
7830   }
7831 
7832   Fl_Menu_Item Logo_menu[] = {
7833     {gettext("M"), 0,  0, 0, 64, 0, 0, 14, 56},
7834     {gettext("Mesh"), 0,  0, 0, 64, 0, 0, 14, 56},
7835     {gettext("None"), 0,  (Fl_Callback*)cb_Logo_None, 0, 0, 0, 0, 14, 56},
7836     {gettext("Square"), 0,  (Fl_Callback*)cb_Logo_Square, 0, 0, 0, 0, 14, 56},
7837     {gettext("Triangle"), 0,  (Fl_Callback*)cb_Logo_Triangle, 0, 0, 0, 0, 14, 56},
7838     {0},
7839     {gettext("View"), 0,  0, 0, 64, 0, 0, 14, 56},
7840     {gettext("Zoom in"), 0,  (Fl_Callback*)cb_Logo_Zoomin, 0, 0, 0, 0, 14, 56},
7841     {gettext("Zoom out"), 0,  (Fl_Callback*)cb_Logo_Zoomout, 0, 0, 0, 0, 14, 56},
7842     {gettext("Right"), 0,  (Fl_Callback*)cb_Logo_Right, 0, 0, 0, 0, 14, 56},
7843     {gettext("Left"), 0,  (Fl_Callback*)cb_Logo_Left, 0, 0, 0, 0, 14, 56},
7844     {gettext("Up"), 0,  (Fl_Callback*)cb_Logo_Up, 0, 0, 0, 0, 14, 56},
7845     {gettext("Down"), 0,  (Fl_Callback*)cb_Logo_Down, 0, 0, 0, 0, 14, 56},
7846     {gettext("ShowPosition"), 0,  (Fl_Callback*)cb_Logo_ShowPosition, 0, 0, 0, 0, 14, 56},
7847     {gettext("HidePosition"), 0,  (Fl_Callback*)cb_Logo_HidePosition, 0, 0, 0, 0, 14, 56},
7848     {0},
7849     {gettext("Export/Print"), 0,  0, 0, 64, 0, 0, 14, 56},
7850     {gettext("EPS/PNG and preview"), 0,  (Fl_Callback*)cb_Logo_Preview, 0, 0, 0, 0, 14, 56},
7851     {gettext("Print"), 0,  (Fl_Callback*)cb_Logo_Print, 0, 0, 0, 0, 14, 56},
7852     {gettext("Preview (with Latex)"), 0,  (Fl_Callback*)cb_Logo_LaTeX_Preview, 0, 0, 0, 0, 14, 56},
7853     {gettext("Print (with Latex)"), 0,  (Fl_Callback*)cb_Logo_LaTeX_Print, 0, 0, 0, 0, 14, 56},
7854     {0},
7855     {gettext("Color"), 0,  (Fl_Callback*)cb_Logo_Color, 0, 0, 0, 0, 14, 56},
7856     {0},
7857     {0}
7858   };
7859 
Logo(int X,int Y,int W,int H,int L)7860   Logo::Logo(int X,int Y,int W,int H,int L):Fl_Tile(X,Y,W,H){
7861     Fl_Tile::end();
7862     scroll_position = -1;
7863     box(FL_FLAT_BOX);
7864     if (L>H/2)
7865       L=H/2;
7866     Fl_Group::current(this);
7867     xcas::HScroll * s = new xcas::HScroll (X,Y,W/4,H);
7868     s->box(FL_FLAT_BOX);
7869     hp = new History_Pack (X,Y,max(W/4-20,W/5),max(H-L-20,20));
7870     // hp->new_question=new_question_multiline_input;
7871     hp->labelsize(L);
7872     hp->pretty_output=false;
7873     hp->eval_below=false;
7874     hp->eval=xcas::Logo_eval;
7875     hp->_insert=xcas::Xcas_pack_insert;
7876     hp->_select=xcas::Xcas_pack_select;
7877     hp->end();
7878     s->end();
7879     t =  new Turtle(X+W/4,Y,W/2,H-L);
7880     t->labelsize(L);
7881     t->turtleptr=&giac::turtle_stack(context0); // will be overwritten by new_logo in History.cc
7882     t->turtlezoom=2;
7883     int bw=(W/2-5*L/2)/14;
7884     button_group = new Fl_Group(X+W/4,Y+H-L,bw*14,L);
7885     int bx=button_group->x(),by=button_group->y();
7886     No_Focus_Button * avance = new No_Focus_Button(bx,by,bw,L);
7887     avance->label(gettext("fw"));
7888     avance->tooltip(gettext("Turtle n steps forward"));
7889     avance->callback((Fl_Callback *) cb_Logo_button);
7890     bx += bw;
7891     No_Focus_Button * recule = new No_Focus_Button(bx,by,bw,L);
7892     recule->label(gettext("bw"));
7893     recule->tooltip(gettext("Turtle n steps backward"));
7894     recule->callback((Fl_Callback *) cb_Logo_button);
7895     bx += bw;
7896     No_Focus_Button * td = new No_Focus_Button(bx,by,bw,L);
7897     td->label(gettext("tr"));
7898     td->tooltip(gettext("Turtle turns right n degrees"));
7899     td->callback((Fl_Callback *) cb_Logo_button);
7900     bx += bw;
7901     No_Focus_Button * tg = new No_Focus_Button(bx,by,bw,L);
7902     tg->label(gettext("tl"));
7903     tg->tooltip(gettext("Turtle turns left n degrees"));
7904     tg->callback((Fl_Callback *) cb_Logo_button);
7905     bx += bw;
7906     No_Focus_Button * pc = new No_Focus_Button(bx,by,bw,L);
7907     pc->label(gettext("ss"));
7908     pc->tooltip(gettext("Turtle steps to the left from n steps"));
7909     pc->callback((Fl_Callback *) cb_Logo_button);
7910     bx += bw;
7911     No_Focus_Button * sa = new No_Focus_Button(bx,by,bw,L);
7912     sa->label(gettext("ju"));
7913     sa->tooltip(gettext("Turtle jumps n steps"));
7914     sa->callback((Fl_Callback *) cb_Logo_button);
7915     bx += bw;
7916     No_Focus_Button * cr = new No_Focus_Button(bx,by,bw,L);
7917     cr->label(gettext("pe"));
7918     cr->tooltip(gettext("Change pen color"));
7919     cr->callback((Fl_Callback *) cb_Logo_button);
7920     bx += bw;
7921     No_Focus_Button * ro = new No_Focus_Button(bx,by,bw,L);
7922     ro->label(gettext("ci"));
7923     ro->tooltip(gettext("Circle arc"));
7924     ro->callback((Fl_Callback *) cb_Logo_button);
7925     bx += bw;
7926     No_Focus_Button * di = new No_Focus_Button(bx,by,bw,L);
7927     di->label(gettext("di"));
7928     di->tooltip(gettext("Filled circle arc"));
7929     di->callback((Fl_Callback *) cb_Logo_button);
7930     bx += bw;
7931     No_Focus_Button * rp = new No_Focus_Button(bx,by,bw,L);
7932     rp->label(gettext("fr"));
7933     rp->tooltip(gettext("Filled rectangle"));
7934     rp->callback((Fl_Callback *) cb_Logo_button);
7935     bx += bw;
7936     No_Focus_Button * tp = new No_Focus_Button(bx,by,bw,L);
7937     tp->label(gettext("ft"));
7938     tp->tooltip(gettext("Filled triangle"));
7939     tp->callback((Fl_Callback *) cb_Logo_button);
7940     bx += bw;
7941     No_Focus_Button * ec = new No_Focus_Button(bx,by,bw,L);
7942     ec->label(gettext("ec"));
7943     ec->tooltip(gettext("Write to the right of the turtle"));
7944     ec->callback((Fl_Callback *) cb_Logo_button);
7945     bx += bw;
7946     No_Focus_Button * sg = new No_Focus_Button(bx,by,bw,L);
7947     sg->label(gettext("sg"));
7948     sg->tooltip(gettext("Sign picture"));
7949     sg->callback((Fl_Callback *) cb_Logo_button);
7950     bx += bw;
7951     No_Focus_Button * ef = new No_Focus_Button(bx,by,bw,L);
7952     ef->label(gettext("cl"));
7953     ef->tooltip(gettext("Clear all"));
7954     ef->callback((Fl_Callback *) cb_Logo_button);
7955     button_group->end();
7956     menubar = new Fl_Menu_Bar(button_group->x()+button_group->w(),button_group->y(),W/2-button_group->w(),L);
7957     int ls= Logo_menu->size();
7958     Fl_Menu_Item * menuitem = new Fl_Menu_Item[Logo_menu->size()];
7959     for (int i=0;i<ls;++i)
7960       *(menuitem+i)=*(Logo_menu+i);
7961     menubar->menu (menuitem);
7962     menubar->tooltip(gettext("Turtle menu"));
7963     ed = new Editeur(X+W/4+W/2,Y,W/4,H);
7964     // ed->callback(History_Pack_cb_eval,0);
7965     ed->extension="tor";
7966     ed->editor->buffer()->insert(0,"efface ;\n");
7967     ed->editor->insert_position(9);
7968     hp->add_entry(-1);
7969     hp->resize();
7970     parent_redraw(this);
7971   }
7972 
handle(int event)7973   int Logo::handle(int event){
7974     if (event==FL_MOUSEWHEEL){
7975       if (!Fl::event_inside(this))
7976 	return 0;
7977       if (Fl::focus()==t){
7978 	int res=t->handle(event);
7979 	if (res)
7980 	  return res;
7981       }
7982       if (!Fl::event_inside(hp->parent()))
7983 	return 0;
7984       return hp->parent()->handle(event);
7985     }
7986     return Fl_Tile::handle(event);
7987   }
7988 
draw()7989   void Logo::draw(){
7990     Fl_Tile::draw();
7991     if (scroll_position>0 && hp){
7992       if (Fl_Scroll * scroll = dynamic_cast<Fl_Scroll *>(hp->parent())){
7993 #ifdef _HAVE_FL_UTF8_HDR_
7994 	scroll->scroll_to(0,scroll_position);
7995 #else
7996 	scroll->position(0,scroll_position);
7997 #endif
7998 	scroll_position=-1;
7999 	Fl_Tile::draw();
8000       }
8001     }
8002   }
8003 
resize(int X,int Y,int W,int H)8004   void Logo::resize(int X,int Y,int W,int H){
8005     Fl_Tile::resize(X,Y,W,H);
8006     int L=labelsize();
8007     if (L>H/2)
8008       L=H/2;
8009     int hph=hp->h();
8010     Fl_Group * g =  hp->parent();
8011     if (Fl_Scroll * scroll = dynamic_cast<Fl_Scroll *>(g))
8012       scroll_position = scroll->yposition();
8013     g->resize(X,Y,W/4,H);
8014     hp->Fl_Group::resize(X,Y,max(W/4-20,W/5),hph);
8015     hp->resize();
8016     t->resize(X+W/4,Y,W/2,H-L);
8017     int bw=(W/2-5*L/2)/14*14;
8018     button_group->resize(X+W/4,Y+H-L,bw,L);
8019     menubar->resize(X+W/4+bw,Y+H-L,W/2-bw,L);
8020     ed->resize(X+W/4+W/2,Y,W/4,H);
8021   }
8022 
fltk_fl_widget_archive_function(ostream & os,void * ptr)8023   ostream & fltk_fl_widget_archive_function(ostream & os,void * ptr){
8024     Fl_Widget * w=(Fl_Widget *) ptr;
8025     const context * contextptr=get_context(w);
8026     Graph2d *i=dynamic_cast<Graph2d *>(w);
8027     if (!i)
8028       return archive(os,string2gen("Done",false),contextptr);
8029     os << _POINTER_ << " " << _FL_WIDGET_POINTER << '\n';
8030     archive(os,i->plot_instructions,contextptr);
8031     archive(os,makevecteur(i->x(),i->y(),i->w(),i->h(),i->window_xmin,i->window_xmax,i->window_ymin,i->window_ymax),contextptr);
8032     return os;
8033   }
8034 
fltk_fl_widget_unarchive_function(istream & os)8035   gen fltk_fl_widget_unarchive_function(istream & os){
8036     // FIXME GIAC_CONTEXT
8037     gen gplot=unarchive(os,context0),gparam=unarchive(os,context0);
8038     if (gplot.type!=_VECT || gparam.type!=_VECT || gparam._VECTptr->size()<8)
8039       return 0;
8040     vecteur v=*gparam._VECTptr;
8041     Fl_Group::current(0);
8042     Graph2d * ptr= new Graph2d(v[0].val,v[1].val,v[2].val,v[3].val,"");
8043     ptr->plot_instructions=vecteur(*gplot._VECTptr);
8044     ptr->window_xmin=v[4]._DOUBLE_val;
8045     ptr->window_xmax=v[5]._DOUBLE_val;
8046     ptr->window_ymin=v[6]._DOUBLE_val;
8047     ptr->window_ymax=v[7]._DOUBLE_val;
8048     return gen(ptr,_FL_WIDGET_POINTER);
8049   }
8050 
fltk_fl_widget_texprint_function(void * ptr)8051   std::string fltk_fl_widget_texprint_function(void * ptr){
8052     static int counter=0;
8053     Fl_Widget * w=(Fl_Widget *) ptr;
8054     Graph2d * i=dynamic_cast<Graph2d *>(w);
8055     ++counter;
8056     double horiz_unit=horiz_latex/(i->window_xmax-i->window_xmin);
8057     double vert_unit=vert_latex/(i->window_ymax-i->window_ymin);
8058     double unit=horiz_unit;
8059     if (horiz_unit>vert_unit)
8060       unit=vert_unit;
8061     string tmpfilename("#tmp"+print_INT_(counter));
8062     FILE * out =fopen(tmpfilename.c_str(),"w");
8063     if (!out)
8064       return "Write error";
8065     if (!graph2tex(out,i->plot_instructions,i->window_xmin,i->window_xmax,i->window_ymin,i->window_ymax,unit,tmpfilename.c_str(),false,get_context(i)))
8066       return "Graph2tex Error";
8067     fclose(out);
8068     FILE * in=fopen(tmpfilename.c_str(),"r");
8069     if (!in)
8070       return "Read Error";
8071     string res;
8072     while (!feof(in))
8073       res += fgetc(in);
8074     return res;
8075   }
8076 
8077   extern Multiline_Input_tab * Xcas_multiline_input;
8078 
8079   // adjust history level to the slider value, and eval history pack
8080   // if eval_hp is true
adjust(bool eval_hp)8081   void Gen_Value_Slider::adjust(bool eval_hp){
8082     Fl_Group * g = parent(); // param_group or tile
8083     if (!g) return;
8084     g=parent_skip_scroll(g); // mouse_param_group or history_pack
8085     if (!g) return;
8086     History_Pack * hp=0;
8087     int position=pos;
8088     if (pos==-2){
8089       hp=dynamic_cast<History_Pack *>(g);
8090       if (hp){
8091 	for (int i=0;i<hp->children();i++){
8092 	  if (hp->child(i)==parent()){
8093 	    position=i;
8094 	    break;
8095 	  }
8096 	}
8097       }
8098     }
8099     else {
8100       g=parent_skip_scroll(g); // parent of Graph2d screen
8101       if (!g) return;
8102       // Now find an history_pack inside g
8103       int n=g->children();
8104       for (int i=0;i<n;++i){
8105 	Fl_Widget * wid = g->child(i);
8106 	if (Fl_Scroll * s=dynamic_cast<Fl_Scroll *>(wid))
8107 	  if (s->children())
8108 	    wid=s->child(0);
8109 	if ( (hp=dynamic_cast<History_Pack *>(wid)) )
8110 	  break;
8111       } // end for i
8112     }
8113     if (hp){
8114       // check that level is gvs->g := ...
8115       unsigned m=hp->children();
8116       if (position>=0 && position<int(m)){
8117 	bool do_cb=false;
8118 	giac::gen gt(hp->value(position),hp->contextptr);
8119 	if (gt.is_symb_of_sommet(at_sto) && gt._SYMBptr->feuille.type==_VECT && !gt._SYMBptr->feuille._VECTptr->empty() ){
8120 	  // Check for element
8121 	  gen & f = gt._SYMBptr->feuille._VECTptr->front();
8122 	  if (f.is_symb_of_sommet(at_element)){
8123 	    gen ff = f._SYMBptr->feuille;
8124 	    if (ff.type==_VECT && !ff._VECTptr->empty())
8125 	      ff = ff._VECTptr->front();
8126 	    // Change gt value with parameter
8127 	    ff = symbolic(at_element,gen(makevecteur(ff,value(),Fl_Valuator::step()),_SEQ__VECT));
8128 	    gt=symbolic(at_sto,makevecteur(ff,gt._SYMBptr->feuille._VECTptr->back()));
8129 	    do_cb=true;
8130 	  }
8131 	} // end element
8132 	if (gt.is_symb_of_sommet(at_assume)){
8133 	  gen & f = gt._SYMBptr->feuille;
8134 	  if (f.is_symb_of_sommet(at_equal)||f.is_symb_of_sommet(at_same)){
8135 	    gen & ff = f._SYMBptr->feuille;
8136 	    if (ff.type==_VECT && !ff._VECTptr->empty()){
8137 	      vecteur v=*ff._VECTptr;
8138 	      if (v.back().type==_VECT && v.back()._VECTptr->size()>=3){
8139 		vecteur & vb=*v.back()._VECTptr;
8140 		gen step=(vb[2]-vb[1])/100;
8141 		if (vb.size()>3)
8142 		  step=vb[3];
8143 		v.back()=makevecteur(value(),vb[1],vb[2],step);
8144 	      }
8145 	      else
8146 		v.back()=makevecteur(value(),minimum(),maximum(),Fl_Valuator::step());
8147 	      gt = symbolic(at_equal,v);
8148 	      gt = symbolic(at_assume,gt);
8149 	      do_cb = true;
8150 	    }
8151 	  }
8152 	  if (f.is_symb_of_sommet(at_sto)){
8153 	    gen & ff = f._SYMBptr->feuille;
8154 	    if (ff.type==_VECT && !ff._VECTptr->empty()){
8155 	      vecteur v=*ff._VECTptr;
8156 	      if (v.front().type==_VECT && v.front()._VECTptr->size()>=3){
8157 		vecteur & vf=*v.front()._VECTptr;
8158 		gen step=(vf[2]-vf[1])/100.;
8159 		if (vf.size()>3)
8160 		  step=vf[3];
8161 		v.front()=makevecteur(value(),vf[1],vf[2],step);
8162 	      }
8163 	      else
8164 		v.front() = makevecteur(value(),minimum(),maximum(),Fl_Valuator::step());
8165 	      gt = symbolic(at_sto,v);
8166 	      gt = symbolic(at_assume,gt);
8167 	      do_cb = true;
8168 	    }
8169 	  }
8170 	} // end assume
8171 	if (do_cb){
8172 	  hp->update_pos=position;
8173 	  if (pos==-2)
8174 	    hp->eval_below=true;
8175 	  gen curseur=protecteval(gt,1,hp->contextptr);
8176 	  Graph2d3d * graph=find_graph2d3d(hp);
8177 	  if (curseur.is_symb_of_sommet(at_parameter) && graph){
8178 	    vecteur & v=graph->plot_instructions;
8179 	    if (position>=0 && v.size()>position){
8180 	      gen & vp=v[position];
8181 	      if (vp.is_symb_of_sommet(at_parameter) && vp._SYMBptr->feuille[0]==curseur._SYMBptr->feuille[0])
8182 		vp=curseur;
8183 	    }
8184 	  }
8185 	  // check how to update (parameter in a figure or in history)
8186 	  Fl_Group * gr = hp->widget_group(position);
8187 	  if (gr && gr->children()>=3){
8188 	    if (dynamic_cast<Fl_Output*>(gr->child(2))){
8189 	      hp->update_pos=position;
8190 	      hp->set_gen_value(position,gt,true);
8191 	      return;
8192 	    }
8193 	  }
8194 	  hp->set_gen_value(position,gt,false);
8195 	  if (eval_hp && hp->children()>position+1){
8196 	    hp->update_pos=position+1;
8197 	    gt=hp->parse(position+1);
8198 	    if (!is_undef(gt))
8199 	      hp->set_gen_value(position+1,gt,true);
8200 	  }
8201 	} // end do_cb
8202       } // end if gvs->pos<children()
8203     } // end if history_pack hp
8204   }
8205 
get_figure(Fl_Widget * widget)8206   Figure * get_figure(Fl_Widget * widget){
8207     for (;widget;){
8208       if (Figure * f =dynamic_cast<Figure *>(widget))
8209 	return f;
8210       widget = widget->parent();
8211     }
8212     return 0;
8213   }
8214 
handle(int event)8215   int Gen_Value_Slider::handle(int event){
8216     string tmp;
8217     Figure * f=get_figure(this);
8218     int position=pos;
8219     History_Pack * hp=f?f->geo->hp:get_history_pack(this,position);
8220     double tmin=minimum(),tmax=maximum(),tcur=value(),tstep=Fl_Valuator::step();
8221     // tstep=100*tstep/(tmax-tmin);
8222     if ((event==FL_PUSH || event==FL_DRAG || event==FL_RELEASE) &&Fl::event_button()== FL_RIGHT_MOUSE){
8223       if (event==FL_RELEASE && hp->children()>position){
8224 	Fl_Widget * wid=hp->child(position);
8225 	while (Fl_Group * s=dynamic_cast<Fl_Group *>(wid)) {
8226 	  if (dynamic_cast<Xcas_Text_Editor *>(wid))
8227 	    break;
8228 	  if (s->children())
8229 	    wid=s->child(0);
8230 	}
8231 	if (Multiline_Input_tab * m=dynamic_cast<Multiline_Input_tab *>(wid)){
8232 	  gen g=m->g();
8233 	  if (figure_param_dialog(hp,true,tmin,tmax,tcur,tstep,paramname,g.is_symb_of_sommet(at_assume),tmp) ){
8234 	    minimum(tmin);
8235 	    maximum(tmax);
8236 	    value(tcur);
8237 	    // tstep=tstep*(tmax-tmin)/100.;
8238 	    step(tstep,10*tstep);
8239 	    redraw();
8240 	    label(paramname.c_str());
8241 	    hp->set_value(position,tmp,true);
8242 	    // if (!f)
8243 	      hp->eval_below=true;
8244 	  }
8245 	}
8246 	if (Xcas_Text_Editor * m=dynamic_cast<Xcas_Text_Editor *>(wid)){
8247 	  gen g=m->g();
8248 	  if (figure_param_dialog(hp,true,tmin,tmax,tcur,tstep,paramname,g.is_symb_of_sommet(at_assume),tmp) ){
8249 	    minimum(tmin);
8250 	    maximum(tmax);
8251 	    value(tcur);
8252 	    // tstep=tstep*(tmax-tmin)/100.;
8253 	    step(tstep,10*tstep);
8254 	    redraw();
8255 	    label(paramname.c_str());
8256 	    hp->set_value(position,tmp,true);
8257 	    // if (!f)
8258 	      hp->eval_below=true;
8259 	  }
8260 	}
8261       }
8262       return 1;
8263     }
8264     return Fl_Counter::handle(event);
8265   }
8266 
Gen_Value_Slider(int x,int y,int w,int h,int _pos,double m,double M,double mystep,const std::string & pname)8267   Gen_Value_Slider::Gen_Value_Slider(int x,int y,int w,int h,int _pos,double m,double M,double mystep,const std::string & pname):Fl_Counter(x,y,w,h),pos(_pos) {
8268     // type(FL_HOR_NICE_SLIDER);
8269     // type(FL_HOR_FILL_SLIDER);
8270     minimum(m); maximum(M);
8271     if (mystep>(M-m)/2 || mystep<0)
8272       mystep=(M-m)/2;
8273     step(mystep,10*mystep);
8274     // slider_size(0.05);
8275     callback(gen_value_slider_cb);
8276     paramname=pname;
8277     label(paramname.c_str());
8278     align(FL_ALIGN_LEFT);
8279   }
8280 
gen_value_slider_cb(Fl_Widget * widget,void *)8281   void gen_value_slider_cb(Fl_Widget * widget,void *){
8282     if (Gen_Value_Slider * gvs=dynamic_cast<Gen_Value_Slider *>(widget))
8283       gvs->adjust(true);
8284   }
8285 
Xcas_xyztrange(const gen & g,GIAC_CONTEXT)8286   gen Xcas_xyztrange(const gen & g,GIAC_CONTEXT){
8287     gen res=_xyztrange(g,contextptr);
8288     // Search if focus is inside a Graph2d group, if so adapt current cfg
8289     Fl_Widget * w = Fl::focus();
8290     Graph2d3d * gr=0;
8291     Figure * fig = 0;
8292     for (;w;){
8293       if ( (gr=dynamic_cast<Graph2d3d *>(w)) )
8294 	break;
8295       if ( (fig=dynamic_cast<Figure *>(w)) ){
8296 	gr = fig->geo;
8297 	break;
8298       }
8299       w = w->parent();
8300     }
8301     if (gr){
8302       gr->window_xmin=global_window_xmin;
8303       gr->window_xmax=global_window_xmax;
8304       gr->window_ymin=global_window_ymin;
8305       gr->window_ymax=global_window_ymax;
8306       // gr->window_zmin=global_window_zmin;
8307       // gr->window_zmax=global_window_zmax;
8308       gr->show_axes=giac::show_axes(contextptr);
8309     }
8310     return res;
8311   }
8312 
draw()8313   void Line_Type::draw(){
8314     xcas_color(color());
8315     fl_rectf(x(),y(),w(),h());
8316     int color=(line_type_ & 0xffff);
8317     xcas_color(color);
8318     fl_rect(x(),y(),w(),h());
8319     int width           =(line_type_ & 0x00070000) >> 16; // 3 bits
8320     int epaisseur_point =(line_type_ & 0x00380000) >> 19; // 3 bits
8321     epaisseur_point += 2;
8322     int type_line       =(line_type_ & 0x01c00000) >> 22; // 3 bits
8323     if (type_line>4)
8324       type_line=(type_line-4)<<8;
8325     int type_point      =(line_type_ & 0x0e000000) >> 25; // 3 bits
8326     int labelpos        =(line_type_ & 0x30000000) >> 28; // 2 bits
8327     bool fill_polygon   =(line_type_ & 0x40000000) >> 30;
8328     bool hidden_name    =(line_type_ & 0x80000000) >> 30;
8329     if (show_line_){
8330       fl_line_style(type_line,width+1,0);
8331       xcas_color(color);
8332       fl_line(x(),y()+h()/2,x()+w(),y()+h()/2);
8333       fl_line_style(0); // back to default line style
8334     }
8335     if (show_pnt_){
8336       xcas_color(color);
8337       fltk_point(x(),y(),w()/2,h()/2-2,epaisseur_point,type_point);
8338     }
8339     if (show_text_ && !hidden_name){
8340       xcas_color(color);
8341       fl_font(FL_HELVETICA,14);
8342       int dx=2,dy=0;
8343       if (labelpos==1 || labelpos==2)
8344 	dx=-14;
8345       if (labelpos==2 || labelpos==3)
8346 	dy=+14;
8347       fl_draw("A",x()+w()/2+dx,y()+h()/2-2+dy);
8348     }
8349     if (show_poly_){
8350       xcas_color(color);
8351       if (fill_polygon)
8352 	fl_pie(x()+w()/2,y()+h()/2,w()/2,h()/2,0,360);
8353       else
8354 	fl_arc(x()+w()/2,y()+h()/2,w()/2,h()/2,0,360);
8355     }
8356   }
8357 
Line_Type(int x,int y,int w,int h,int lt)8358   Line_Type::Line_Type(int x,int y,int w,int h,int lt):Fl_Button(x,y,w,h),line_type_(lt),show_pnt_(false),show_line_(true),show_text_(false),show_poly_(false) {
8359     box(FL_UP_FRAME);
8360     color(FL_WHITE);
8361   }
8362 
line_type(int l)8363   void Line_Type::line_type(int l){
8364     line_type_=l;
8365     damage(FL_DAMAGE_ALL);
8366   }
8367 
8368 
8369 #ifndef NO_NAMESPACE_XCAS
8370 } // namespace giac
8371 #endif // ndef NO_NAMESPACE_XCAS
8372 
8373 #endif // HAVE_LIBFLTK
8374