1 // -*- mode:C++ ; compile-command: "g++ -I.. -g -c Print.cc" -*-
2 /*
3  *  Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #ifndef IN_GIAC
23 #include <giac/first.h>
24 #else
25 #include "first.h"
26 #endif
27 #include <string>
28 #ifdef HAVE_LIBFLTK
29 #include "Print.h"
30 #include <FL/Fl.H>
31 #include <FL/fl_draw.H>
32 #include <FL/Fl_Window.H>
33 #include <FL/fl_ask.H>
34 #include <FL/Fl_Hold_Browser.H>
35 #include <FL/Fl_Value_Input.H>
36 #include <FL/Fl_Return_Button.H>
37 #include "History.h"
38 #include "Equation.h"
39 #include "Graph.h"
40 #include "Graph3d.h"
41 #include "Tableur.h"
42 #include <iostream>
43 #include <fstream>
44 
45 using namespace std;
46 using namespace giac;
47 
48 #ifdef FL_DEVICE
49 
50 //#include <FL/Fl_Printer.H>
51 #include <FL/Fl_PS_Printer.H>
52 
53 #ifdef WIN32
54   #include <FL/Fl_GDI_Printer.H>
55 #endif
56 
57 #include <FL/fl_printer_chooser.H>
58 
59   #include "Fl_PS_Printer.cxx"
60 
61 #ifdef WIN32
62   #include "Fl_GDI_Printer.cxx"
63 #endif
64 
65 #define Fl_PostScript_Graphics_Driver Fl_PS_Printer
66 #define Fl_PostScript_File_Device Fl_PS_Printer
67 #define Fl_PrintDevice Fl_Printer
68 #else // FL_DEVICE
69 #include <FL/Fl_PostScript.H>
70 #define Fl_PrintDevice Fl_Paged_Device
71 #endif // FL_DEVICE
72 
73 
74 
75 #ifndef NO_NAMESPACE_XCAS
76 namespace xcas {
77 #endif // ndef NO_NAMESPACE_XCAS
78 
79 #ifdef FL_DEVICE
80   double pixel_scale=0.21*FL_MM; // 1000 pixels=21 cm
81 #else
82   double FL_MM=1.0;
83   double FL_INCH=23.0;
84   double pixel_scale=1; // should be fixed to work with scales
85 #endif
86 
change_background_color(Fl_Widget * w,int c,int newc)87   int change_background_color(Fl_Widget * w,int c,int newc){
88     int oldc=w->color();
89     if (oldc==c)
90       w->color(newc);
91     if (Fl_Group * g=dynamic_cast<Fl_Group *>(w)){
92       int n=g->children();
93       for (int i=0;i<n;++i)
94 	change_background_color(g->child(i),c,newc);
95     }
96     return oldc;
97   }
98 
99 #ifdef Fl_Printer_H
100 #ifdef FL_DEVICE
101   int printer_format=Fl_Printer::A4;
102 #else
103   int printer_format=Fl_Paged_Device::A4;
104 #endif
105 #else // Fl_Printer_H
106   int printer_format=-1;
107 #endif // Fl_Printer_H
108   bool printer_landscape=false;
109 
110 #ifdef FL_DEVICE
111 
ck_page_height(Fl_Printer * p)112   unsigned ck_page_height(Fl_Printer * p){
113     int h=p->page_height();
114     if (h<=0){
115       cerr << "Bad page height " << h << '\n';
116       h=806;
117     }
118   }
119 
ck_page_width(Fl_Printer * p)120   unsigned ck_page_width(Fl_Printer * p){
121     int w=p->page_width();
122     if (w<=0){
123       cerr << "Bad page width " << w << '\n';
124       w=559;
125     }
126   }
127 
print_newpage(Fl_Printer * p)128   void print_newpage(Fl_Printer * p){
129     if (printer_landscape)
130       p->page(printer_format | Fl_Printer::LANDSCAPE);
131     else
132       p->page(printer_format);
133   }
134 
Flv_Table_Gen_widget_print(Flv_Table_Gen * g,Fl_Printer * p,bool eps)135   void Flv_Table_Gen_widget_print(Flv_Table_Gen * g,Fl_Printer * p,bool eps){
136     print_newpage(p);
137     double margin=FL_INCH;
138     int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
139     int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
140     g->resize(0,0,wp,hp);
141     int i=0,j=0; // current row/column
142     for (;j<g->cols()-1;){
143       if (i || j)
144 	print_newpage(p);
145       g->row(g->rows());
146       g->col(g->cols());
147       g->select_start_row(g->rows());
148       g->select_start_col(g->cols());
149       g->redraw();
150       g->row(i);
151       g->col(j);
152       g->select_start_row(i);
153       g->select_start_col(j);
154       g->redraw();
155       p->place(0.0, 0.0, margin,margin, pixel_scale);
156       fl_draw(g);
157       i = g->get_row(100,hp-20);
158       i = max(i,g->get_row(100,hp-25));
159       i = max(i,g->get_row(95,hp-20));
160       i = max(i,g->get_row(95,hp-25));
161       if (i<0)
162 	i=g->rows();
163       if (i>=g->rows()-3){
164 	i=0;
165 	g->row(i);
166 	j=g->get_col(wp-30,hp-20);
167 	j=max(j,g->get_col(wp-30,hp-25));
168 	j=max(j,g->get_col(wp-35,hp-20));
169 	j=max(j,g->get_col(wp-35,hp-25));
170 	if (j<0)
171 	  j=g->cols();
172       }
173     }
174   }
175 
Equation_widget_print(Equation * g,Fl_Printer * p,bool eps)176   void Equation_widget_print(Equation * g,Fl_Printer * p,bool eps){
177     print_newpage(p);
178     int x=g->x(),y=g->y();//,h=g->h(),w=g->w();
179     eqwdata e=Equation_total_size(g->data);
180     double margin=FL_INCH;
181     int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
182     int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
183     g->resize(x,y,wp,hp);
184     int np=e.dy/hp;
185     for (int i=0;i<=np;++i){
186       if (i)
187 	print_newpage(p);
188       //if (i)
189       //p->page(Fl_Printer::A4);
190       // fprintf(f,"%sPage: %d %d\n","%%",i+1,i+1);
191       g->xleft=e.x;
192       g->ytop=e.y+e.dy-i*hp;
193       p->place(g->xleft, 0, margin,margin, pixel_scale);
194       fl_draw(g);
195     }
196   }
197 
Graph2d3d_widget_print(Graph2d3d * i,Fl_Printer * p,bool eps)198   void Graph2d3d_widget_print(Graph2d3d * i,Fl_Printer * p,bool eps){
199     Graph3d * g3=dynamic_cast<Graph3d *>(i);
200     if (g3){
201       if (Fl_PS_Printer * ps=dynamic_cast<Fl_PS_Printer * >(p))
202 	g3->printing=ps->file();
203     }
204     int x=i->x(),y=i->y(),w=i->w(),h=i->h();
205     if (eps){
206       i->resize(0,0,w,h);
207       p->place(0.0,0.0,0.0,0.0,pixel_scale);
208     }
209     else {
210       print_newpage(p);
211       double margin=FL_INCH;
212       int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
213       int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
214       if (wp*h<hp*w)
215 	i->resize(0,0,wp,(h*wp)/w);
216       else
217 	i->resize(0,0,(hp*w)/h,hp);
218       p->place(0.0, 0.0, margin,margin, pixel_scale);
219     }
220     fl_draw(i);
221     i->resize(x,y,w,h);
222     if (g3)
223       g3->printing=0;
224   }
225 
generic_widget_print(Fl_Widget * i,Fl_Printer * p,bool eps)226   void generic_widget_print(Fl_Widget * i,Fl_Printer * p,bool eps){
227     int x=i->x(),y=i->y(),w=i->w(),h=i->h();
228     if (eps){
229       i->resize(0,0,w,h);
230       p->place(0.0,0.0,0.0,0.0,pixel_scale);
231     }
232     else {
233       print_newpage(p);
234       double margin=FL_INCH;
235       int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
236       int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
237       if (wp*h<hp*w)
238 	i->resize(0,0,wp,(h*wp)/w);
239       else
240 	i->resize(0,0,(hp*w)/h,hp);
241       p->place(0.0, 0.0, margin,margin, pixel_scale);
242     }
243     fl_draw(i);
244     i->resize(x,y,w,h);
245   }
246 
Fl_Text_Editor_widget_print(Fl_Text_Editor * g,Fl_Printer * p,bool eps)247   void Fl_Text_Editor_widget_print(Fl_Text_Editor * g,Fl_Printer * p,bool eps){
248     print_newpage(p);
249     Fl_Text_Buffer * b=g->buffer();
250     double margin=FL_INCH;
251     int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
252     int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
253     int endpos=string(b->text()).size();
254     int nlines=b->count_lines(0,endpos)+1;
255     int t=g->textsize();
256     int npoints=nlines*t,np=npoints/hp;
257     if (npoints%hp)
258       np += 1;
259     // np=numbre of pages, adjust hp
260     int ligneparpage=nlines/np;
261     if (nlines%np){
262       ligneparpage +=1 ;
263       /*
264       int j=np*ligneparpage-nlines;
265       // insert blank lines at end
266       string ins;
267       for (;j;--j)
268 	ins += " \n";
269       b->insert(endpos-1,ins.c_str());
270       */
271     }
272     hp=ligneparpage*t+g->scrollbar_width()+10;
273     g->resize(0,0,wp,hp);
274     for (int i=0;i<np;++i){
275       if (i)
276 	print_newpage(p);
277       if (i==np-1)
278 	g->resize(0,0,wp,(nlines-i*ligneparpage)*t+g->scrollbar_width()+10);
279       g->scroll(i*ligneparpage+1,0);
280       p->place(0.0, 0.0, margin,margin, pixel_scale);
281       fl_draw(g);
282     }
283   }
284 
setgraph3dprintstate(Fl_Widget * widget,FILE * stream,bool hidemouseparam)285   void setgraph3dprintstate(Fl_Widget * widget,FILE * stream,bool hidemouseparam){
286     Fl_Group * g=dynamic_cast<Fl_Group *>(widget);
287     if (!g)
288       return;
289     int n=g->children();
290     for (int i=0;i<n;++i){
291       Fl_Widget * wid = g->child(i);
292       if (Fl_Group * gr=dynamic_cast<Fl_Group * >(wid))
293 	setgraph3dprintstate(gr,stream,hidemouseparam);
294       if (Graph2d3d * gr=dynamic_cast<Graph2d3d * >(wid)){
295 	if (gr->mouse_param_group){
296 	  Fl_Group * G=gr->parent();
297 	  if (stream){
298 	    if (hidemouseparam)
299 	      gr->mouse_param_group->hide();
300 	  }
301 	  else {
302 	    gr->mouse_param_group->show();
303 	    if (G){ // restore correct sizes
304 	      gr->resize(gr->x(),gr->y(),G->w()+G->x()-gr->x()-gr->legende_size,gr->h());
305 	      gr->resize_mouse_param_group(gr->legende_size);
306 	    }
307 	  }
308 	}
309 	if (Graph3d * gr3=dynamic_cast<Graph3d * >(wid))
310 	  gr3->printing=stream;
311       }
312     }
313   }
314 
315   // scan s children for last y() <= pos
scan(Fl_Group * s,int pos,int hp)316   int scan(Fl_Group * s,int pos,int hp){
317     if (s->y()+s->h()<=pos)
318       return s->y()+s->h();
319     int n=s->children(),i;
320     int curpos=0;
321     for (i=0;i<n;++i){
322       int y=s->child(i)->y();
323       if (y>pos)
324 	break;
325       else
326 	curpos=y;
327     }
328     if (curpos<pos-hp/3)
329       return pos;
330     else
331       return curpos;
332   }
333 
History_Pack_widget_print(History_Pack * g,Fl_Printer * p,bool eps)334   void History_Pack_widget_print(History_Pack * g,Fl_Printer *p,bool eps){
335     // Save parent widget and position
336     Fl_Group * gp=g->parent();
337     if (!gp)
338       return;
339     int pos=gp->find(g);
340     print_newpage(p);
341     int x=g->x(),y=g->y(),h=g->h(),w=g->w();
342     double margin=FL_INCH;
343     int hp=int((ck_page_height(p)-2*margin)/pixel_scale);
344     int wp=int((ck_page_width(p)-2*margin)/pixel_scale);
345     // Create a scroll group of size hp/wp and put g in it
346     Fl_Group::current(0);
347     Fl_Window * win = new Fl_Window(0,0,wp,hp);
348     Fl_Scroll * s = new Fl_Scroll(0,0,wp,hp);
349     s->end();
350     win->end();
351     s->color(g->color());
352     s->box(FL_FLAT_BOX);
353     s->add(g);
354     g->Fl_Group::resize(0,0,wp-g->labelsize(),h);
355     g->resize();
356     int ypos=0,newpos=0;
357     for (;ypos<h;){
358       if (ypos)
359 	print_newpage(p);
360 #ifdef _HAVE_FL_UTF8_HDR_
361       s->scroll_to(0,0);
362 #else
363       s->position(0,0);
364 #endif
365       newpos=scan(g,ypos+hp,hp);
366       s->resize(0,0,wp,newpos-ypos);
367 #ifdef _HAVE_FL_UTF8_HDR_
368       s->scroll_to(0,ypos);
369 #else
370       s->position(0,ypos);
371 #endif
372       p->place(0.0,0, margin,margin, pixel_scale);
373       fl_draw(s);
374       ypos = newpos;
375     }
376     // Restore g in parent widget
377     g->Fl_Group::resize(x,y,w,h);
378     g->resize();
379     gp->insert(*g,pos);
380     delete s;
381   }
382 
inner_widget_print(Fl_Widget * widget,Fl_Printer * p,bool eps)383   void inner_widget_print(Fl_Widget * widget,Fl_Printer * p,bool eps){
384     if (History_Pack * f=dynamic_cast<History_Pack *>(widget)){
385       History_Pack_widget_print(f,p,eps);
386       return ;
387     }
388     if (Fl_Text_Editor * b=dynamic_cast<Fl_Text_Editor *>(widget)){
389       Fl_Text_Editor_widget_print(b,p,eps);
390       return;
391     }
392     if (Equation * g = dynamic_cast<Equation *> (widget)){
393       Equation_widget_print(g,p,eps);
394       return;
395     }
396     if (Graph2d3d * i=dynamic_cast<Graph2d3d *>(widget)){
397       Graph2d3d_widget_print(i,p,eps);
398       return;
399     }
400     if (Flv_Table_Gen * t=dynamic_cast<Flv_Table_Gen *>(widget)){
401       Flv_Table_Gen_widget_print(t,p,eps);
402       return;
403     }
404     generic_widget_print(widget,p,eps);
405     /*
406     if (Fl_Group * gr=dynamic_cast<Fl_Group *>(widget)){
407       // print all elements of the group
408       int n=gr->children();
409       for (int i=0;i<n;++i)
410 	inner_widget_print(gr->child(i),p,eps);
411       return;
412     }
413     */
414   }
415 
in_widget_print(Fl_Widget * widget,Fl_Printer * p,bool eps)416   void in_widget_print(Fl_Widget * widget,Fl_Printer * p,bool eps){
417     if (!widget) return;
418     bool screen_capture=false;
419     if (dynamic_cast<Fl_Window *>(widget))
420       screen_capture=true;
421     if (!screen_capture)
422       change_background_color(widget,Xcas_background_color,7);
423     Fl_Output_Device * c = p->set_current();
424     int x=widget->x(),y=widget->y(),h=widget->h(),w=widget->w();
425     inner_widget_print(widget,p,eps);
426     widget->resize(x,y,w,h);
427     if (!screen_capture){
428       change_background_color(widget,7,Xcas_background_color);
429       set_colors(widget);
430     }
431     c->set_current();
432   }
433 
434 #else // FL_DEVICE
435 
436 #ifdef Fl_Printer_H
437 
print_newpage(Fl_PrintDevice * p)438   void print_newpage(Fl_PrintDevice * p){
439     p->start_page();
440   }
endpage(Fl_PrintDevice * p)441   void endpage(Fl_PrintDevice *p){
442     p->end_page();
443   }
444 
compute_w_h(Fl_PrintDevice * p,double margin,double pixel_scale,int & wp,int & hp)445   void compute_w_h(Fl_PrintDevice *p,double margin,double pixel_scale,int & wp,int &hp){
446     p->printable_rect(&wp,&hp);
447     if (wp<=1){
448       cerr << "Bad width " << wp << '\n';
449       wp=559;
450     }
451     if (hp<=1){
452       cerr << "Bad height " << hp << '\n';
453       hp=806;
454     }
455   }
do_print(Fl_Widget * w,Fl_PrintDevice * p,double margin,double pixel_scale)456   void do_print(Fl_Widget * w,Fl_PrintDevice *p,double margin,double pixel_scale){
457     p->print_widget(w,0,0);
458   }
459 
Flv_Table_Gen_widget_print(Flv_Table_Gen * g,Fl_PrintDevice * p,bool eps)460   void Flv_Table_Gen_widget_print(Flv_Table_Gen * g,Fl_PrintDevice * p,bool eps){
461     print_newpage(p);
462     double margin=FL_INCH;
463     int hp,wp;
464     compute_w_h(p,margin,pixel_scale,wp,hp);
465     g->resize(0,0,wp,hp);
466     int i=0,j=0; // current row/column
467     for (;j<g->cols()-1;){
468       if (i || j)
469 	print_newpage(p);
470       g->row(g->rows());
471       g->col(g->cols());
472       g->select_start_row(g->rows());
473       g->select_start_col(g->cols());
474       g->redraw();
475       g->row(i);
476       g->col(j);
477       g->select_start_row(i);
478       g->select_start_col(j);
479       g->redraw();
480       do_print(g,p,margin,pixel_scale);
481       endpage(p);
482       i = g->get_row(100,hp-20);
483       i = max(i,g->get_row(100,hp-25));
484       i = max(i,g->get_row(95,hp-20));
485       i = max(i,g->get_row(95,hp-25));
486       if (i<0)
487 	i=g->rows();
488       if (i>=g->rows()-3){
489 	i=0;
490 	g->row(i);
491 	j=g->get_col(wp-30,hp-20);
492 	j=max(j,g->get_col(wp-30,hp-25));
493 	j=max(j,g->get_col(wp-35,hp-20));
494 	j=max(j,g->get_col(wp-35,hp-25));
495 	if (j<0)
496 	  j=g->cols();
497       }
498     }
499   }
500 
Equation_widget_print(Equation * g,Fl_PrintDevice * p,bool eps)501   void Equation_widget_print(Equation * g,Fl_PrintDevice * p,bool eps){
502     print_newpage(p);
503     int x=g->x(),y=g->y();//,h=g->h(),w=g->w();
504     eqwdata e=Equation_total_size(g->data);
505     double margin=FL_INCH;
506     int hp,wp;
507     compute_w_h(p,margin,pixel_scale,wp,hp);
508     g->resize(x,y,wp,hp);
509     int np=e.dy/hp;
510     for (int i=0;i<=np;++i){
511       if (i)
512 	print_newpage(p);
513       //if (i)
514       //p->page(Fl_PrintDevice::A4);
515       // fprintf(f,"%sPage: %d %d\n","%%",i+1,i+1);
516       g->xleft=e.x;
517       g->ytop=e.y+e.dy-i*hp;
518       p->print_widget(g,g->xleft,0);
519       endpage(p);
520     }
521   }
522 
523   class ps_file_device:public Fl_PostScript_File_Device {
524   public:
driver()525     Fl_PostScript_Graphics_Driver * driver() { return Fl_PostScript_File_Device::driver(); };
ps_file_device()526     ps_file_device():Fl_PostScript_File_Device(){};
527   };
528 
Graph2d3d_widget_print(Graph2d3d * i,Fl_PrintDevice * p,bool eps)529   void Graph2d3d_widget_print(Graph2d3d * i,Fl_PrintDevice * p,bool eps){
530     Graph3d * g3=dynamic_cast<Graph3d *>(i);
531     if (g3){
532       if (ps_file_device * ps=dynamic_cast<ps_file_device * >(p)){
533 	g3->printing=ps->driver()->file();
534       }
535     }
536     int x=i->x(),y=i->y(),w=i->w(),h=i->h();
537     if (eps){
538       i->resize(0,0,w,h);
539       print_newpage(p);
540       do_print(i,p,0,pixel_scale);
541     }
542     else {
543       print_newpage(p);
544       double margin=FL_INCH;
545       int hp,wp;
546       compute_w_h(p,margin,pixel_scale,wp,hp);
547       if (wp*h<hp*w)
548 	i->resize(0,0,wp,(h*wp)/w);
549       else
550 	i->resize(0,0,(hp*w)/h,hp);
551       do_print(i,p,margin,pixel_scale);
552       endpage(p);
553     }
554     i->resize(x,y,w,h);
555     if (g3)
556       g3->printing=0;
557   }
558 
generic_widget_print(Fl_Widget * i,Fl_PrintDevice * p,bool eps)559   void generic_widget_print(Fl_Widget * i,Fl_PrintDevice * p,bool eps){
560     int x=i->x(),y=i->y(),w=i->w(),h=i->h();
561     if (eps){
562       print_newpage(p);
563       i->resize(0,0,w,h);
564       do_print(i,p,0,pixel_scale);
565       // endpage(p);
566     }
567     else {
568       print_newpage(p);
569       double margin=FL_INCH;
570       int hp,wp;
571       compute_w_h(p,margin,pixel_scale,wp,hp);
572       if (wp*h<hp*w)
573 	i->resize(0,0,wp,(h*wp)/w);
574       else
575 	i->resize(0,0,(hp*w)/h,hp);
576       do_print(i,p,margin,pixel_scale);
577       endpage(p);
578     }
579     i->resize(x,y,w,h);
580   }
581 
Fl_Text_Editor_widget_print(Fl_Text_Editor * g,Fl_PrintDevice * p,bool eps)582   void Fl_Text_Editor_widget_print(Fl_Text_Editor * g,Fl_PrintDevice * p,bool eps){
583     print_newpage(p);
584     Fl_Text_Buffer * b=g->buffer();
585     double margin=FL_INCH;
586     int hp,wp;
587     compute_w_h(p,margin,pixel_scale,wp,hp);
588     int endpos=string(b->text()).size();
589     int nlines=b->count_lines(0,endpos)+1;
590     int t=g->textsize();
591     int npoints=nlines*t,np=npoints/hp;
592     if (npoints%hp)
593       np += 1;
594     // np=numbre of pages, adjust hp
595     int ligneparpage=nlines/np;
596     if (nlines%np){
597       ligneparpage +=1 ;
598       /*
599       int j=np*ligneparpage-nlines;
600       // insert blank lines at end
601       string ins;
602       for (;j;--j)
603 	ins += " \n";
604       b->insert(endpos-1,ins.c_str());
605       */
606     }
607     hp=ligneparpage*t+g->scrollbar_width()+10;
608     g->resize(0,0,wp,hp);
609     for (int i=0;i<np;++i){
610       if (i)
611 	print_newpage(p);
612       if (i==np-1)
613 	g->resize(0,0,wp,(nlines-i*ligneparpage)*t+g->scrollbar_width()+10);
614       g->scroll(i*ligneparpage+1,0);
615       do_print(g,p,margin,pixel_scale);
616       endpage(p);
617     }
618   }
619 
620   // also show or hide mouse param group
setgraph3dprintstate(Fl_Widget * widget,FILE * stream,bool hidemouseparam)621   void setgraph3dprintstate(Fl_Widget * widget,FILE * stream,bool hidemouseparam){
622     Fl_Group * g=dynamic_cast<Fl_Group *>(widget);
623     if (!g)
624       return;
625     int n=g->children();
626     for (int i=0;i<n;++i){
627       Fl_Widget * wid = g->child(i);
628       if (Fl_Group * gr=dynamic_cast<Fl_Group * >(wid))
629 	setgraph3dprintstate(gr,stream,hidemouseparam);
630       if (Graph2d3d * gr=dynamic_cast<Graph2d3d * >(wid)){
631 	if (gr->mouse_param_group){
632 	  Fl_Group * G=gr->parent();
633 	  if (stream){
634 	    if (hidemouseparam)
635 	      gr->mouse_param_group->hide();
636 	  }
637 	  else {
638 	    gr->mouse_param_group->show();
639 	    if (G){ // restore correct sizes
640 	      gr->resize(gr->x(),gr->y(),G->w()+G->x()-gr->x()-gr->legende_size,gr->h());
641 	      gr->resize_mouse_param_group(gr->legende_size);
642 	    }
643 	  }
644 	}
645 	if (Graph3d * gr3=dynamic_cast<Graph3d * >(wid))
646 	  gr3->printing=stream;
647       }
648     }
649   }
650 
651   // scan s children for last y() <= pos
scan(Fl_Group * s,int pos,int hp)652   int scan(Fl_Group * s,int pos,int hp){
653     if (s->y()+s->h()<=pos)
654       return s->y()+s->h();
655     int n=s->children(),i;
656     int curpos=0;
657     for (i=0;i<n;++i){
658       int y=s->child(i)->y();
659       if (y>pos)
660 	break;
661       else
662 	curpos=y;
663     }
664     if (curpos<pos-hp/3)
665       return pos;
666     else
667       return curpos;
668   }
669 
History_Pack_widget_print(History_Pack * g,Fl_PrintDevice * p,bool eps)670   void History_Pack_widget_print(History_Pack * g,Fl_PrintDevice *p,bool eps){
671     // Save parent widget and position
672     Fl_Group * gp=g->parent();
673     if (!gp)
674       return;
675     int pos=gp->find(g);
676     print_newpage(p);
677     int x=g->x(),y=g->y(),h=g->h(),w=g->w();
678     double margin=FL_INCH;
679     int hp,wp;
680     compute_w_h(p,margin,pixel_scale,wp,hp);
681     // Create a scroll group of size hp/wp and put g in it
682     Fl_Group::current(0);
683     Fl_Window * win = new Fl_Window(0,0,wp,hp);
684     Fl_Scroll * s = new Fl_Scroll(0,0,wp,hp);
685     s->end();
686     win->end();
687     s->color(g->color());
688     s->box(FL_FLAT_BOX);
689     s->add(g);
690     g->Fl_Group::resize(0,0,wp-g->labelsize(),h);
691     g->resize();
692     int ypos=0,newpos=0;
693     for (;ypos<h;){
694       if (ypos)
695 	print_newpage(p);
696 #ifdef _HAVE_FL_UTF8_HDR_
697       s->scroll_to(0,0);
698 #else
699       s->position(0,0);
700 #endif
701       newpos=scan(g,ypos+hp,hp);
702       s->resize(0,0,wp,newpos-ypos);
703 #ifdef _HAVE_FL_UTF8_HDR_
704       s->scroll_to(0,ypos);
705 #else
706       s->position(0,ypos);
707 #endif
708       do_print(s,p,margin,pixel_scale);
709       endpage(p);
710       ypos = newpos;
711     }
712     // Restore g in parent widget
713     g->Fl_Group::resize(x,y,w,h);
714     g->resize();
715     gp->insert(*g,pos);
716     delete s;
717   }
718 
inner_widget_print(Fl_Widget * widget,Fl_PrintDevice * p,bool eps)719   void inner_widget_print(Fl_Widget * widget,Fl_PrintDevice * p,bool eps){
720     if (History_Pack * f=dynamic_cast<History_Pack *>(widget)){
721       History_Pack_widget_print(f,p,eps);
722       return ;
723     }
724     if (Fl_Text_Editor * b=dynamic_cast<Fl_Text_Editor *>(widget)){
725       Fl_Text_Editor_widget_print(b,p,eps);
726       return;
727     }
728     if (Equation * g = dynamic_cast<Equation *> (widget)){
729       Equation_widget_print(g,p,eps);
730       return;
731     }
732     if (Graph2d3d * i=dynamic_cast<Graph2d3d *>(widget)){
733       Graph2d3d_widget_print(i,p,eps);
734       return;
735     }
736     if (Flv_Table_Gen * t=dynamic_cast<Flv_Table_Gen *>(widget)){
737       Flv_Table_Gen_widget_print(t,p,eps);
738       return;
739     }
740     generic_widget_print(widget,p,eps);
741     /*
742     if (Fl_Group * gr=dynamic_cast<Fl_Group *>(widget)){
743       // print all elements of the group
744       int n=gr->children();
745       for (int i=0;i<n;++i)
746 	inner_widget_print(gr->child(i),p,eps);
747       return;
748     }
749     */
750   }
751 
in_widget_print(Fl_Widget * widget,Fl_PrintDevice * p,bool eps)752   void in_widget_print(Fl_Widget * widget,Fl_PrintDevice * p,bool eps){
753     if (!widget) return;
754     bool screen_capture=false;
755     if (dynamic_cast<Fl_Window *>(widget))
756       screen_capture=true;
757     if (!screen_capture)
758       change_background_color(widget,Xcas_background_color,7);
759     int x=widget->x(),y=widget->y(),h=widget->h(),w=widget->w();
760     inner_widget_print(widget,p,eps);
761     widget->resize(x,y,w,h);
762     if (!screen_capture){
763       change_background_color(widget,7,Xcas_background_color);
764       set_colors(widget);
765     }
766   }
767 #endif // Fl_Printer_H
768 
769 #endif // FL_DEVICE
770 
771 #ifdef WIN32
772   string ps_preview="!";
773 #else
774 #ifdef __APPLE__
775   string ps_preview="open"; // "/Applications/Preview.app/Contents/MacOS/Preview";
776 #else
777   string ps_preview="gv";
778 #endif
779 #endif
780 
new_widget_size(int & neww,int & newh)781   bool new_widget_size(int & neww,int & newh){
782     static Fl_Window * w = 0;
783     static Fl_Value_Input * fw=0, *fh=0,* pxl=0;
784     static Fl_Return_Button * button0 = 0 ;
785     static Fl_Button * button1 =0;
786     if (!w){
787       int dx=300, dy=100;
788       Fl_Group::current(0);
789       w=new Fl_Window(dx,dy);
790       fw=new Fl_Value_Input(dx/4,2,dx/4-2,dy/3-4,gettext("Width"));
791       fw->tooltip(gettext("Width in pixels for export"));
792       fh=new Fl_Value_Input(3*dx/4,2,dx/4-2,dy/3-4,gettext("Height"));
793       fh->tooltip(gettext("Height in pixels for export"));
794       pxl=new Fl_Value_Input(3*dx/4,2+dy/3,dx/4-2,dy/3-4,gettext("Pixel size"));
795       pxl->tooltip(gettext("Pixel size in mm"));
796       button0 = new Fl_Return_Button(2,2+2*dy/3,dx/2-4,dy/3-4);
797       button0->shortcut(0xff0d);
798       button0->label(gettext("OK"));
799       button1 = new Fl_Button(dx/2+2,2+2*dy/3,dx/2-4,dy/3-4);
800       button1->shortcut(0xff1b);
801       button1->label(gettext("Cancel"));
802       w->end();
803       w->resizable(w);
804       w->label(gettext("Size in pixels for export"));
805     }
806     fw->value(neww);
807     fh->value(newh);
808     pxl->value(pixel_scale/FL_MM);
809     int r=-1;
810     w->set_modal();
811     w->show();
812     w->hotspot(w);
813     Fl::focus(w);
814     for (;;) {
815       Fl_Widget *o = Fl::readqueue();
816       if (!o) Fl::wait();
817       else {
818 	if (o == button0) {r = 0; break;}
819 	if (o == button1) {r = 1; break;}
820 	if (o == w) { r=1; break; }
821       }
822     }
823     w->hide();
824     if (r)
825       return false;
826     neww=int(std::max(1.0,fw->value()));
827     newh=int(std::max(1.0,fh->value()));
828     pixel_scale=pxl->value()*FL_MM;
829     return true;
830   }
831 
widget_ps_print(Fl_Widget * widget,const std::string & fname0,bool eps,int pngpdf,bool preview,bool hidemouseparam,bool askusersize)832   void widget_ps_print(Fl_Widget * widget,const std::string & fname0,bool eps,int pngpdf,bool preview,bool hidemouseparam,bool askusersize){
833     if (!eps)
834       pngpdf=0;
835 #ifdef Fl_Printer_H
836     // Fl_PrintDevice * p = fl_printer_chooser();
837     int x=widget->x(),y=widget->y(),w=widget->w(),h=widget->h(),neww(giacmin(w,570)),newh(h*double(neww)/w);
838     if (!askusersize && neww==570)
839       newh=300;
840     if (eps){
841       if (askusersize && !new_widget_size(neww,newh))
842 	return;
843       widget->resize(x,y,neww,newh);
844     }
845     string fname1=replace(fname0,' ','_');
846     if (fname1.empty())
847       fname1="session";
848     if (fname1[0]=='<')
849       fname1="session";
850     string fname(remove_extension(fname1)+(eps?".eps":".ps"));
851     if (!eps || pngpdf){
852       char * filename = file_chooser(eps?"Print to EPS/PNG/PDF file":"Print to PS file",eps?"*.eps":"*.ps",fname.c_str());
853       if(!filename) return;
854       fname=remove_extension(filename)+(eps?".eps":".ps");
855     }
856     FILE * f = fopen(fname.c_str(),"w");
857     if(!f) return;
858     Fl_PrintDevice * p;
859 #ifdef FL_DEVICE
860     if (eps)
861       p= new Fl_PS_Printer(f, 3,0,0,int(widget->w()*pixel_scale),int(widget->h()*pixel_scale));
862     else
863       p=new Fl_PS_Printer(f, 3);
864 #else
865     ps_file_device * ptr=new ps_file_device();
866     if (!ptr) return;
867     ptr->driver()->pw_=eps?int(widget->w()*pixel_scale):0;
868     ptr->driver()->ph_=eps?int(widget->h()*pixel_scale):0;
869     ptr->start_job(f,eps?0:3);
870     p=ptr;
871 #endif
872     if (p){
873       // Scan all graph3d widget inside and move their state to printing=p stream
874 #ifdef FL_DEVICE
875       if (Fl_PostScript_File_Device * ps=dynamic_cast<Fl_PostScript_File_Device * >(p)){
876 	setgraph3dprintstate(widget,ps->file(),hidemouseparam);
877       }
878 #else
879       if (ps_file_device * ps=dynamic_cast<ps_file_device * >(p)){
880 	setgraph3dprintstate(widget,ps->driver()->file(),hidemouseparam);
881       }
882 #endif
883       in_widget_print(widget,p,eps);
884 #ifndef FL_DEVICE
885       p->end_job();
886 #endif
887       // Scan all graph3d widget inside and move their state to printing=true
888       setgraph3dprintstate(widget,0,false);
889 #ifdef FL_DEVICE
890       delete p;
891 #else
892       delete ptr;
893 #endif
894     }
895     fclose(f); //we need close file here
896     if (getenv("GIAC_PREVIEW"))
897       ps_preview=getenv("GIAC_PREVIEW");
898 #ifdef WIN32
899     if (ps_preview=="!"){
900       ps_preview="/cygdrive/c/";
901       if (getenv("XCAS_ROOT")){
902 	string s(getenv("XCAS_ROOT"));
903 	if (s.substr(0,10)=="/cygdrive/")
904 	  ps_preview[10]=s[10];
905       }
906       ps_preview +="Program\\ Files/Ghostgum/gsview/gsview32.exe";
907     }
908     pngpdf |= 0x4;
909 #endif
910     // translate into png, (inside GIMP Image->Transform->rotate, not anymore)
911     // inside latex use includegraphics[width=\textwidth{filename}
912     // FIXME add pstopnm pnmtopng libnetpbm to the window mac distributions
913     if (eps){
914       widget->resize(x,y,w,h);
915 #ifndef WIN32 // def __APPLE__
916       if (pngpdf & 0x1)
917 	system_no_deprecation(("convert "+fname+" "+remove_extension(fname)+".png &").c_str());
918       if (pngpdf & 0x2)
919 	system_no_deprecation(("convert "+fname+" "+remove_extension(fname)+".pdf &").c_str());
920       if (pngpdf & 0x4)
921 	system_no_deprecation(("convert "+fname+" "+remove_extension(fname)+".jpg &").c_str());
922 #else
923 #ifdef WIN32
924       if (pngpdf & 0x4)
925 	system_no_deprecation((xcasroot()+"pstopnm -stdout -portrait '"+fname+"' | "+xcasroot()+"pnmtojpeg > '"+remove_extension(fname)+".jpg'").c_str());
926       if (pngpdf & 0x1)
927 	system_no_deprecation((xcasroot()+"pstopnm -stdout -portrait '"+fname+"' | "+xcasroot()+"pnmtopng > '"+remove_extension(fname)+".png' &").c_str());
928       if (pngpdf & 0x2){
929 	// epstopdf is a perl script, it won't work wo perl
930 	system_no_deprecation(("cp -f '"+fname+"' tmpeps.eps && epstopdf tmpeps.eps && cp -f tmpeps.pdf '"+remove_extension(fname)+".pdf' &").c_str());
931       }
932 #else // not used anymore, assuming convert is avail. on linux
933       if (pngpdf & 0x1)
934 	system_no_deprecation(("pstopnm -stdout -portrait "+fname+" | pnmtopng > "+remove_extension(fname)+".png &").c_str());
935       if (pngpdf & 0x2)
936 	system_no_deprecation(("epstopdf "+fname+" &").c_str());
937       if (pngpdf & 0x4)
938 	system_no_deprecation(("pstopnm -stdout -portrait "+fname+" | pnmtojpeg > "+remove_extension(fname)+".jpg &").c_str());
939 #endif
940 #endif
941     }
942     // Preview
943     if (ps_preview!="no" && preview){
944 #ifdef WIN32
945       system_browser_command(fname);
946       /*
947       string fn=absolute_path(fname);
948       if (system_no_deprecation((((ps_preview+" ")+fn)+" &").c_str())){
949 	cerr << (("cygstart.exe '"+remove_extension(fname)+".jpg' &").c_str()) << '\n';
950 	system_no_deprecation((xcasroot()+"cygstart.exe '"+remove_extension(fname)+".jpg' &").c_str());
951       }
952       */
953 #else
954       system_no_deprecation((((ps_preview+" ")+fname)+" &").c_str());
955 #endif
956     }
957     if (eps && pngpdf){
958       fname=remove_path(remove_extension(fname));
959       unsigned fnames=fname.size();
960       static string tmp;
961       tmp=fname+".eps/.png ready for import.\nUse \\includegraphics[width=\\textwidth]{"+fname+"}\nwhere [] is optional, width may also be e.g. 10cm\ninside your latex document, with header\n\\usepackage{graphicx}\n(PNG export requires pstopnm and pnmtopng)";
962       if (Xcas_help_output){
963 	Xcas_help_output->value(tmp.c_str());
964 	Xcas_help_output->position(32+fnames,68+2*fnames);
965 	Fl::copy(Xcas_help_output->Fl_Output::value()+32+fnames,36+fnames,0);
966 	Fl::copy(Xcas_help_output->Fl_Output::value()+32+fnames,36+fnames,1);
967 	Fl::focus(Xcas_help_output);
968       }
969       else
970 	fl_message("%s",tmp.c_str());
971     }
972 #endif
973   }
974 
widget_print(Fl_Widget * widget)975   void widget_print(Fl_Widget * widget){
976 #ifdef Fl_Printer_H
977 #ifdef FL_DEVICE
978     Fl_PrintDevice * p = fl_printer_chooser();
979     if (p){
980       // Scan all graph3d widget inside and move their state to printing=p stream
981       if (Fl_PostScript_Graphics_Driver * ps=dynamic_cast<Fl_PostScript_Graphics_Driver * >(p))
982 	setgraph3dprintstate(widget,ps->file(),true);
983       in_widget_print(widget,p,false);
984       delete p;
985       // Scan all graph3d widget inside and move their state to printing=true
986       setgraph3dprintstate(widget,0,false);
987     }
988 #else
989     Fl_Printer * p = new Fl_Printer();
990     if (p->start_job(1))
991       return; // unable to print
992     if (p){
993       // Scan all graph3d widget inside and move their state to printing=p stream
994       if (Fl_PostScript_Graphics_Driver * ps=dynamic_cast<Fl_PostScript_Graphics_Driver * >(p))
995 	setgraph3dprintstate(widget,ps->file(),true);
996       in_widget_print(widget,p,false);
997       p->end_job();
998       delete p;
999       // Scan all graph3d widget inside and move their state to printing=true
1000       setgraph3dprintstate(widget,0,false);
1001     }
1002 #endif
1003 #endif
1004   }
1005 
1006 #ifndef NO_NAMESPACE_XCAS
1007 } // namespace xcas
1008 #endif // ndef NO_NAMESPACE_XCAS
1009 
1010 #endif // HAVE_LIBFLTK
1011