1 // -*- mode:C++ ; compile-command: "g++-3.4 -I. -I.. -g -c Equation.cc -DHAVE_CONFIG_H -DIN_GIAC -Wall" -*-
2 /*
3  *  Copyright (C) 2005,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 #include "config.h"
19 #include "giacPCH.h"
20 #ifdef NSPIRE_NEWLIB
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <os.h>
24 #include <syscall.h>
25 #endif
26 #ifdef KHICAS
27 #include "kdisplay.h"
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #include <ctype.h>
33 #include "input_lexer.h"
34 #include "input_parser.h"
35 //giac::context * contextptr=0;
36 int clip_ymin=0;
37 int lang=1;
38 bool warn_nr=true;
39 bool xthetat=false;
40 bool freezeturtle=false;
41 int esc_flag=0;
42 int xcas_python_eval=0;
43 using namespace std;
44 using namespace giac;
45 const int LCD_WIDTH_PX=320;
46 const int LCD_HEIGHT_PX=222;
47 char* fmenu_cfg=0;
48 int khicas_addins_menu(GIAC_CONTEXT); // in kadd.cc
49 #ifdef MICROPY_LIB
50 extern "C" const char * const * mp_vars();
51 #endif
52 
53 // Numworks Logo commands
54 #ifndef NO_NAMESPACE_GIAC
55 namespace giac {
56 #endif // ndef NO_NAMESPACE_GIAC
Bdisp_PutDisp_DD()57   void Bdisp_PutDisp_DD(){
58     sync_screen();
59   }
Bdisp_AllClr_VRAM()60   void Bdisp_AllClr_VRAM(){
61     waitforvblank();
62     drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE);
63   }
drawLine(int x1,int y1,int x2,int y2,int c)64   void drawLine(int x1,int y1,int x2,int y2,int c){
65     draw_line(x1,y1,x2,y2,c,context0);
66   }
stroke_rectangle(int x,int y,int w,int h,int c)67   void stroke_rectangle(int x,int y,int w,int h,int c){
68     drawLine(x,y,x+w,y,c);
69     drawLine(x,y+h,x+w,y+h,c);
70     drawLine(x,y,x,y+h,c);
71     drawLine(x+w,y,x+w,y+h,c);
72   }
DefineStatusMessage(const char * s,int a,int b,int c)73   void DefineStatusMessage(const char * s,int a,int b,int c){
74     statuslinemsg(s);
75   }
76 
DisplayStatusArea()77   void DisplayStatusArea(){
78     sync_screen();
79   }
80 
set_xcas_status()81   void set_xcas_status(){
82     statusline(1);
83   }
GetSetupSetting(int mode)84   int GetSetupSetting(int mode){
85     return 0;
86   }
87 
SetSetupSetting(int mode,int)88   void SetSetupSetting(int mode,int){
89   }
90 
handle_f5()91   void handle_f5(){
92     lock_alpha();
93   }
94 
delete_clipboard()95   void delete_clipboard(){}
96 
97   bool clip_pasted=true;
98 
clipboard()99   string * clipboard(){
100     static string * ptr=0;
101     if (!ptr)
102       ptr=new string;
103     return ptr;
104   }
105 
copy_clipboard(const string & s,bool status)106   void copy_clipboard(const string & s,bool status){
107     if (1 || clip_pasted) // adding to clipboard is sometimes annoying
108       *clipboard()=s;
109     else
110       *clipboard()+=s;
111     clip_pasted=false;
112     if (status){
113       DefineStatusMessage((char*)((lang==1)?"Selection copiee vers presse-papiers.":"Selection copied to clipboard"), 1, 0, 0);
114       DisplayStatusArea();
115     }
116   }
117 
paste_clipboard()118   const char * paste_clipboard(){
119     clip_pasted=true;
120     return clipboard()->c_str();
121   }
122 
print_msg12(const char * msg1,const char * msg2,int textY=40)123   int print_msg12(const char * msg1,const char * msg2,int textY=40){
124     drawRectangle(0, textY+10, LCD_WIDTH_PX, 44, COLOR_WHITE);
125     drawRectangle(3,textY+10,316,3, COLOR_BLACK);
126     drawRectangle(3,textY+10,3,44, COLOR_BLACK);
127     drawRectangle(316,textY+10,3,44, COLOR_BLACK);
128     drawRectangle(3,textY+54,316,3, COLOR_BLACK);
129     int textX=30;
130     if (msg1){
131       if (strlen(msg1)>=30)
132 	os_draw_string_small_(textX,textY+15,msg1);
133       else
134 	os_draw_string_(textX,textY+15,msg1);
135     }
136     textX=10;
137     textY+=33;
138     if (msg2){
139       if (strlen(msg2)>=30)
140 	os_draw_string_small_(textX,textY,msg2);
141       else
142 	textX=os_draw_string_(textX,textY,msg2);
143     }
144     return textX;
145   }
146 
insert(string & s,int pos,const char * add)147   void insert(string & s,int pos,const char * add){
148     if (pos>s.size())
149       pos=s.size();
150     if (pos<0)
151       pos=0;
152     s=s.substr(0,pos)+add+s.substr(pos,s.size()-pos);
153   }
154 
do_confirm(const char * s)155   bool do_confirm(const char * s){
156 #ifdef NSPIRE_NEWLIB
157     return confirm(s,((lang==1)?"enter: oui,  esc:annuler":"enter: yes,   esc: cancel"))==KEY_CTRL_F1;
158 #else
159     return confirm(s,((lang==1)?"OK: oui,  Back:annuler":"OK: yes,   Back: cancel"))==KEY_CTRL_F1;
160 #endif
161   }
162 
confirm(const char * msg1,const char * msg2,bool acexit,int y)163   int confirm(const char * msg1,const char * msg2,bool acexit,int y){
164     int key=0;
165     print_msg12(msg1,msg2,y);
166     while (key!=KEY_CTRL_F1 && key!=KEY_CTRL_F6){
167       GetKey(&key);
168       if (key==KEY_SHUTDOWN)
169 	return key;
170       if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK)
171 	key=KEY_CTRL_F1;
172       if (key==KEY_CTRL_AC || key==KEY_CTRL_EXIT || key==KEY_CTRL_MENU){
173 	if (acexit) return -1;
174 	key=KEY_CTRL_F6;
175       }
176       set_xcas_status();
177     }
178     return key;
179   }
180 
confirm_overwrite()181   bool confirm_overwrite(){
182 #ifdef NSPIRE_NEWLIB
183     return do_confirm((lang==1)?"enter: oui,  esc:annuler":"enter: yes,   esc: cancel")==KEY_CTRL_F1;
184 #else
185     return do_confirm((lang==1)?"OK: oui,  Back:annuler":"OK: yes,   Back: cancel")==KEY_CTRL_F1;
186 #endif
187   }
188 
invalid_varname()189   void invalid_varname(){
190     confirm((lang==1)?"Nom de variable incorrect":"Invalid variable name",
191 #ifdef NSPIRE_NEWLIB
192 	    (lang==1)?"enter: ok":"enter: ok"
193 #else
194 	    (lang==1)?"OK: ok":"OK: ok"
195 #endif
196 	    );
197   }
198 
199 
200 #ifdef SCROLLBAR
201   typedef scrollbar TScrollbar;
202 #endif
203 
204 #define C24 18 // 24 on 90
205 #define C18 18 // 18
206 #define C10 10 // 18
207 #define C6 6 // 6
208 
MB_ElementCount(const char * s)209   int MB_ElementCount(const char * s){
210     return strlen(s); // FIXME for UTF8
211   }
212 
PrintXY(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE)213   void PrintXY(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE){
214     if (mode==TEXT_MODE_NORMAL)
215       os_draw_string(x,y,c,bg,s);
216     else
217       os_draw_string(x,y,bg,c,s);
218   }
219 
PrintMiniMini(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE,bool fake=false)220   int PrintMiniMini(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE,bool fake=false){
221     if (mode==TEXT_MODE_NORMAL)
222       return os_draw_string_small(x,y,c,bg,s,fake);
223     else
224       return os_draw_string_small(x,y,bg,c,s,fake);
225   }
226 
PrintMini(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE,bool fake=false)227   int PrintMini(int x,int y,const char * s,int mode,int c=giac::_BLACK,int bg=giac::_WHITE,bool fake=false){
228     if (mode==TEXT_MODE_NORMAL)
229       return os_draw_string(x,y,c,bg,s,fake);
230     else
231       return os_draw_string(x,y,bg,c,s,fake);
232   }
233 
printCentered(const char * text,int y)234   void printCentered(const char* text, int y) {
235     int len = strlen(text);
236     int x = LCD_WIDTH_PX/2-(len*6)/2;
237     PrintXY(x,y,text,0);
238   }
239 
doMenu(Menu * menu,MenuItemIcon * icontable)240   int doMenu(Menu* menu, MenuItemIcon* icontable) { // returns code telling what user did. selection is on menu->selection. menu->selection starts at 1!
241     int itemsStartY=menu->startY; // char Y where to start drawing the menu items. Having a title increases this by one
242     int itemsHeight=menu->height;
243     int showtitle = menu->title != NULL;
244     if (showtitle) {
245       itemsStartY++;
246       itemsHeight--;
247     }
248     char keyword[5];
249     keyword[0]=0;
250     if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
251       menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
252     if(menu->selection-1 < menu->scroll)
253       menu->scroll = menu->selection -1;
254 
255     while(1) {
256       // Cursor_SetFlashOff();
257       if (menu->selection <=1)
258 	menu->selection=1;
259       if (menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
260 	menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
261       if (menu->selection-1 < menu->scroll)
262 	menu->scroll = menu->selection -1;
263       if(menu->statusText != NULL) DefineStatusMessage(menu->statusText, 1, 0, 0);
264       // Clear the area of the screen we are going to draw on
265       if(0 == menu->pBaRtR) {
266 	int x=C10*menu->startX-1,
267 	  y=C24*(menu->miniMiniTitle ? itemsStartY:menu->startY)-1,
268 	  w=2+C10*menu->width /* + ((menu->scrollbar && menu->scrollout)?C10:0) */,
269 	  h=2+C24*menu->height-(menu->miniMiniTitle ? C24:0);
270 	// drawRectangle(x, y, w, h, COLOR_WHITE);
271 	draw_line(x,y,x+w,y,COLOR_BLACK,context0);
272 	draw_line(x,y+h,x+w,y+h,COLOR_BLACK,context0);
273 	draw_line(x,y,x,y+h,COLOR_BLACK,context0);
274 	draw_line(x+w,y,x+w,y+h,COLOR_BLACK,context0);
275       }
276       if (menu->numitems>0) {
277 	for(int curitem=0; curitem < menu->numitems; curitem++) {
278 	  // print the menu item only when appropriate
279 	  if(menu->scroll <= curitem && menu->scroll > curitem-itemsHeight) {
280 	    if ((curitem-menu->scroll) % 6==0)
281 	      waitforvblank();
282 	    char menuitem[256] = "";
283 	    if(menu->numitems>=100 || menu->type == MENUTYPE_MULTISELECT){
284 	      strcpy(menuitem, "  "); //allow for the folder and selection icons on MULTISELECT menus (e.g. file browser)
285 	      strcpy(menuitem+2,menu->items[curitem].text);
286 	    }
287 	    else {
288 	      int cur=curitem+1;
289 	      if (menu->numitems<10){
290 		menuitem[0]='0'+cur;
291 		menuitem[1]=' ';
292 		menuitem[2]=0;
293 		strcpy(menuitem+2,menu->items[curitem].text);
294 	      }
295 	      else {
296 		menuitem[0]=cur>=10?('0'+(cur/10)):' ';
297 		menuitem[1]='0'+(cur%10);
298 		menuitem[2]=' ';
299 		menuitem[3]=0;
300 		strcpy(menuitem+3,menu->items[curitem].text);
301 	      }
302 	    }
303 	    //strncat(menuitem, menu->items[curitem].text, 68);
304 	    if(menu->items[curitem].type != MENUITEM_SEPARATOR) {
305 	      //make sure we have a string big enough to have background when item is selected:
306 	      // MB_ElementCount is used instead of strlen because multibyte chars count as two with strlen, while graphically they are just one char, making fillerRequired become wrong
307 	      int fillerRequired = menu->width - MB_ElementCount(menu->items[curitem].text) - (menu->type == MENUTYPE_MULTISELECT ? 2 : 3);
308 	      for(int i = 0; i < fillerRequired; i++)
309 		strcat(menuitem, " ");
310 	      drawRectangle(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),C10*menu->width,C24,(menu->selection == curitem+1 ? _BLACK : _WHITE));
311 	      PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),menuitem, (menu->selection == curitem+1 ? TEXT_MODE_INVERT : TEXT_MODE_NORMAL));
312 	    } else {
313 	      /*int textX = (menu->startX-1) * C18;
314 		int textY = curitem*C24+itemsStartY*C24-menu->scroll*C24-C24+C10;
315 		clearLine(menu->startX, curitem+itemsStartY-menu->scroll, (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE));
316 		drawLine(textX, textY+C24-4, LCD_WIDTH_PX-2, textY+C24-4, COLOR_GRAY);
317 		PrintMini(&textX, &textY, (unsigned char*)menuitem, 0, 0xFFFFFFFF, 0, 0, (menu->selection == curitem+1 ? COLOR_WHITE : textColorToFullColor(menu->items[curitem].color)), (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE), 1, 0);*/
318 	    }
319 	    // deal with menu items of type MENUITEM_CHECKBOX
320 	    if(menu->items[curitem].type == MENUITEM_CHECKBOX) {
321 	      PrintXY(C10*(menu->startX+menu->width-4),C18*(curitem+itemsStartY-menu->scroll),
322 		      (menu->items[curitem].value == MENUITEM_VALUE_CHECKED ? " [+]" : " [-]"),
323 		      (menu->selection == curitem+1 ? TEXT_MODE_INVERT : (menu->pBaRtR == 1? TEXT_MODE_NORMAL : TEXT_MODE_NORMAL)));
324 	    }
325 	    // deal with multiselect menus
326 	    if(menu->type == MENUTYPE_MULTISELECT) {
327 	      if((curitem+itemsStartY-menu->scroll)>=itemsStartY &&
328 		 (curitem+itemsStartY-menu->scroll)<=(itemsStartY+itemsHeight) &&
329 		 icontable != NULL
330 		 ) {
331 #if 0
332 		if (menu->items[curitem].isfolder == 1) {
333 		  // assumes first icon in icontable is the folder icon
334 		  CopySpriteMasked(icontable[0].data, (menu->startX)*C18, (curitem+itemsStartY-menu->scroll)*C24, 0x12, 0x18, 0xf81f  );
335 		} else {
336 		  if(menu->items[curitem].icon >= 0) CopySpriteMasked(icontable[menu->items[curitem].icon].data, (menu->startX)*C18, (curitem+itemsStartY-menu->scroll)*C24, 0x12, 0x18, 0xf81f  );
337 		}
338 #endif
339 	      }
340 	      if (menu->items[curitem].isselected) {
341 		if (menu->selection == curitem+1) {
342 		  PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),"\xe6\x9b", TEXT_MODE_NORMAL);
343 		} else {
344 		  PrintXY(C10*menu->startX,C18*(curitem+itemsStartY-menu->scroll),"\xe6\x9b", TEXT_MODE_NORMAL);
345 		}
346 	      }
347 	    }
348 	  }
349 	} // end for curitem<menu->numitem
350 	int dh=menu->height-menu->numitems-(showtitle?1:0);
351 	if (dh>0)
352 	  drawRectangle(C10*menu->startX,C24*(menu->numitems+(showtitle?1:0)),C10*menu->width,C24*dh,_WHITE);
353 	if (menu->scrollbar) {
354 #ifdef SCROLLBAR
355 	  TScrollbar sb;
356 	  sb.I1 = 0;
357 	  sb.I5 = 0;
358 	  sb.indicatormaximum = menu->numitems;
359 	  sb.indicatorheight = itemsHeight;
360 	  sb.indicatorpos = menu->scroll;
361 	  sb.barheight = itemsHeight*C24;
362 	  sb.bartop = (itemsStartY-1)*C24;
363 	  sb.barleft = menu->startX*C18+menu->width*C18 - C18 - (menu->scrollout ? 0 : 5);
364 	  sb.barwidth = C10;
365 	  Scrollbar(&sb);
366 #endif
367 	}
368 	//if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0) drawFkeyLabels(0x0037); // SELECT (white)
369       } else {
370 	giac::printCentered(menu->nodatamsg, (itemsStartY*C24)+(itemsHeight*C24)/2-12);
371       }
372       if(showtitle) {
373 	int textX = C10*menu->startX, textY=menu->startY*C24;
374 	drawRectangle(textX,textY,C10*menu->width,C24,_WHITE);
375 	if (menu->miniMiniTitle)
376 	  PrintMini( textX, textY, menu->title, 0 );
377 	else
378 	  PrintXY(textX, textY, menu->title, TEXT_MODE_NORMAL);
379 	if(menu->subtitle != NULL) {
380 	  int textX=(MB_ElementCount(menu->title)+menu->startX-1)*C18+C10, textY=C10;
381 	  PrintMini(textX, textY, menu->subtitle, 0);
382 	}
383 	PrintXY(textX+C10*(menu->width-5), 1, "____", 0);
384 	PrintXY(textX+C10*(menu->width-5), 1, keyword, 0);
385       }
386       /*if(menu->darken) {
387 	DrawFrame(COLOR_BLACK);
388 	VRAMInvertArea(menu->startX*C18-C18, menu->startY*C24, menu->width*C18-(menu->scrollout || !menu->scrollbar ? 0 : 5), menu->height*C24);
389 	}*/
390       if(menu->type == MENUTYPE_NO_KEY_HANDLING) return MENU_RETURN_INSTANT; // we don't want to handle keys
391       int key;
392       GetKey(&key);
393       if (key==KEY_SHUTDOWN)
394 	return key;
395       if (key==KEY_CTRL_MENU){
396 	menu->selection=menu->numitems;
397 	return MENU_RETURN_SELECTION;
398       }
399       if (key<256 && isalpha(key)){
400 	key=tolower(key);
401 	int pos=strlen(keyword);
402 	if (pos>=4)
403 	  pos=0;
404 	keyword[pos]=key;
405 	keyword[pos+1]=0;
406 	int cur=0;
407 	for (;cur<menu->numitems;++cur){
408 #if 1
409 	  if (strcmp(menu->items[cur].text,keyword)>=0)
410 	    break;
411 #else
412 	  char c=menu->items[cur].text[0];
413 	  if (key<=c)
414 	    break;
415 #endif
416 	}
417 	if (cur<menu->numitems){
418 	  menu->selection=cur+1;
419 	  if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
420 	    menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
421 	  if(menu->selection-1 < menu->scroll)
422 	    menu->scroll = menu->selection -1;
423 	}
424 	continue;
425       }
426       switch(key) {
427       case KEY_CTRL_PAGEDOWN:
428 	menu->selection+=6;
429 	if (menu->selection >= menu->numitems)
430 	  menu->selection=menu->numitems;
431 	if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
432 	  menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
433 	break;
434       case KEY_CTRL_DOWN:
435 	if(menu->selection == menu->numitems)
436 	  {
437 	    if(menu->returnOnInfiniteScrolling) {
438 	      return MENU_RETURN_SCROLLING;
439 	    } else {
440 	      menu->selection = 1;
441 	      menu->scroll = 0;
442 	    }
443 	  }
444 	else
445 	  {
446 	    menu->selection++;
447 	    if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
448 	      menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
449 	  }
450 	if(menu->pBaRtR==1) return MENU_RETURN_INSTANT;
451 	break;
452       case KEY_CTRL_PAGEUP:
453 	menu->selection-=6;
454 	if (menu->selection <=1)
455 	  menu->selection=1;
456 	if(menu->selection-1 < menu->scroll)
457 	  menu->scroll = menu->selection -1;
458 	break;
459       case KEY_CTRL_UP:
460 	if(menu->selection == 1)
461 	  {
462 	    if(menu->returnOnInfiniteScrolling) {
463 	      return MENU_RETURN_SCROLLING;
464 	    } else {
465 	      menu->selection = menu->numitems;
466 	      menu->scroll = menu->selection-(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
467 	    }
468 	  }
469 	else
470 	  {
471 	    menu->selection--;
472 	    if(menu->selection-1 < menu->scroll)
473 	      menu->scroll = menu->selection -1;
474 	  }
475 	if(menu->pBaRtR==1) return MENU_RETURN_INSTANT;
476 	break;
477       case KEY_CTRL_F1:
478 	if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0 && menu->numitems > 0) {
479           /*if(menu->items[menu->selection-1].isselected) {
480             menu->items[menu->selection-1].isselected=0;
481             menu->numselitems = menu->numselitems-1;
482 	    } else {
483             menu->items[menu->selection-1].isselected=1;
484             menu->numselitems = menu->numselitems+1;
485 	    }
486 	    return key; //return on F1 too so that parent subroutines have a chance to e.g. redraw fkeys*/
487 	} else if (menu->type == MENUTYPE_FKEYS) {
488 	  return key;
489 	}
490 	break;
491       case KEY_CTRL_F2:
492       case KEY_CTRL_F3:
493       case KEY_CTRL_F4:
494       case KEY_CTRL_F5:
495       case KEY_CTRL_F6: case KEY_CTRL_CATALOG: case KEY_BOOK: case '\t':
496       case KEY_CHAR_ANS:
497 	if (menu->type == MENUTYPE_FKEYS || menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on Fkeys
498 	break;
499       case KEY_CTRL_PASTE:
500 	if (menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on paste
501       case KEY_CTRL_OPTN:
502 	if (menu->type==MENUTYPE_FKEYS || menu->type==MENUTYPE_MULTISELECT) return key;
503 	break;
504       case KEY_CTRL_FORMAT:
505 	if (menu->type==MENUTYPE_FKEYS) return key; // return on the Format key so that event lists can prompt to change event category
506 	break;
507       case KEY_CTRL_RIGHT:
508 	if(menu->type != MENUTYPE_MULTISELECT) return KEY_BOOK; // break;
509 	// else fallthrough
510       case KEY_CTRL_EXE: case KEY_CTRL_OK:
511 	if(menu->numitems>0) return key==KEY_CTRL_OK?MENU_RETURN_SELECTION:key;
512 	break;
513       case KEY_CTRL_LEFT:
514 	if(menu->type != MENUTYPE_MULTISELECT) break;
515 	// else fallthrough
516       case KEY_CTRL_DEL:
517 	if (strlen(keyword))
518 	  keyword[strlen(keyword)-1]=0;
519 	else {
520 	  if (strcmp(menu->title,"Variables")==0)
521 	    return key;
522 	}
523 	break;
524       case KEY_CTRL_AC:
525 	if (strlen(keyword)){
526 	  keyword[0]=0;
527 	  lock_alpha();//SetSetupSetting( (unsigned int)0x14, 0x88);
528 	  //DisplayStatusArea();
529 	  break;
530 	}
531       case KEY_CTRL_EXIT:
532 	return MENU_RETURN_EXIT;
533 	break;
534       case KEY_CHAR_1:
535       case KEY_CHAR_2:
536       case KEY_CHAR_3:
537       case KEY_CHAR_4:
538       case KEY_CHAR_5:
539       case KEY_CHAR_6:
540       case KEY_CHAR_7:
541       case KEY_CHAR_8:
542       case KEY_CHAR_9:
543 	if(menu->numitems>=(key-0x30)) {
544 	  menu->selection = (key-0x30);
545 	  if (menu->type != MENUTYPE_FKEYS) return MENU_RETURN_SELECTION;
546 	}
547 	break;
548       case KEY_CHAR_0:
549 	if(menu->numitems>=10) {
550 	  menu->selection = 10;
551 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
552 	}
553 	break;
554       case KEY_CHAR_EXPN:
555 	if(menu->numitems>=11) {
556 	  menu->selection = 11;
557 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
558 	}
559 	break;
560       case KEY_CHAR_LN:
561 	if(menu->numitems>=12) {
562 	  menu->selection = 12;
563 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
564 	}
565 	break;
566       case KEY_CHAR_LOG:
567 	if(menu->numitems>=13) {
568 	  menu->selection = 13;
569 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
570 	}
571 	break;
572       case KEY_CHAR_IMGNRY:
573 	if(menu->numitems>=14) {
574 	  menu->selection = 14;
575 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
576 	}
577 	break;
578       case KEY_CHAR_COMMA:
579 	if(menu->numitems>=15) {
580 	  menu->selection = 15;
581 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
582 	}
583 	break;
584       case KEY_CHAR_POW:
585 	if(menu->numitems>=16) {
586 	  menu->selection = 16;
587 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
588 	}
589 	break;
590       case KEY_CHAR_SIN:
591       case KEY_CHAR_COS:
592       case KEY_CHAR_TAN:
593 	if(menu->numitems>=(key-112)) {
594 	  menu->selection = (key-112);
595 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
596 	}
597 	break;
598       case KEY_CHAR_PI:
599 	if(menu->numitems>=20) {
600 	  menu->selection = 20;
601 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
602 	}
603 	break;
604       case KEY_CHAR_ROOT:
605 	if(menu->numitems>=21) {
606 	  menu->selection = 21;
607 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
608 	}
609 	break;
610       case KEY_CHAR_SQUARE:
611 	if(menu->numitems>=22) {
612 	  menu->selection = 22;
613 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
614 	}
615 	break;
616       case KEY_CHAR_LPAR:
617       case KEY_CHAR_RPAR:
618 	if(menu->numitems>=(key-21)) {
619 	  menu->selection = (key-21);
620 	  if (menu->type != MENUTYPE_FKEYS)  return MENU_RETURN_SELECTION;
621 	}
622 	break;
623       }
624     }
625     return MENU_RETURN_EXIT;
626   }
627 
628 #define CAT_CATEGORY_ALL 0
629 #define CAT_CATEGORY_ALGEBRA 1
630 #define CAT_CATEGORY_LINALG 2
631 #define CAT_CATEGORY_CALCULUS 3
632 #define CAT_CATEGORY_ARIT 4
633 #define CAT_CATEGORY_COMPLEXNUM 5
634 #define CAT_CATEGORY_PLOT 6
635 #define CAT_CATEGORY_POLYNOMIAL 7
636 #define CAT_CATEGORY_PROBA 8
637 #define CAT_CATEGORY_PROGCMD 9
638 #define CAT_CATEGORY_REAL 10
639 #define CAT_CATEGORY_SOLVE 11
640 #define CAT_CATEGORY_STATS 12
641 #define CAT_CATEGORY_TRIG 13
642 #define CAT_CATEGORY_OPTIONS 14
643 #define CAT_CATEGORY_LIST 15
644 #define CAT_CATEGORY_MATRIX 16
645 #define CAT_CATEGORY_PROG 17
646 #define CAT_CATEGORY_SOFUS 18
647 #define CAT_CATEGORY_PHYS 19
648 #define CAT_CATEGORY_UNIT 20
649 #define CAT_CATEGORY_LOGO 21 // should be the last one
650 
init_locale()651   void init_locale(){
652     lang=1;
653   }
654 
655   const catalogFunc completeCatfr[] = { // list of all functions (including some not in any category)
656     // {"cosh(x)", 0, "Hyperbolic cosine of x.", 0, 0, CAT_CATEGORY_TRIG},
657     // {"exp(x)", 0, "Renvoie e^x.", "1.2", 0, CAT_CATEGORY_REAL},
658     // {"log(x)", 0, "Logarithme naturel de x.", 0, 0, CAT_CATEGORY_REAL},
659     // {"sinh(x)", 0, "Hyperbolic sine of x.", 0, 0, CAT_CATEGORY_TRIG},
660     // {"tanh(x)", 0, "Hyperbolic tangent of x.", 0, 0, CAT_CATEGORY_TRIG},
661     {" boucle for (pour)", "for ", "Boucle definie pour un indice variant entre 2 valeurs fixees", "#\nfor ", 0, CAT_CATEGORY_PROG},
662     {" boucle liste", "for in", "Boucle sur tous les elements d'une liste.", "#\nfor in", 0, CAT_CATEGORY_PROG},
663     {" boucle while (tantque)", "while ", "Boucle indefinie tantque.", "#\nwhile ", 0, CAT_CATEGORY_PROG},
664     {" test si alors", "if ", "Test", "#\nif ", 0, CAT_CATEGORY_PROG},
665     {" test sinon", "else ", "Clause fausse du test", 0, 0, CAT_CATEGORY_PROG},
666     {" fonction def.", "f(x):=", "Definition de fonction.", "#\nf(x):=", 0, CAT_CATEGORY_PROG},
667     {" local j,k;", "local ", "Declaration de variables locales Xcas", 0, 0, CAT_CATEGORY_PROG},
668     {" range(a,b)", "in range(", "Dans l'intervalle [a,b[ (a inclus, b exclus)", "# in range(1,10)", 0, CAT_CATEGORY_PROG},
669     {" return res;", "return ", "return ou retourne quitte la fonction et renvoie le resultat res", 0, 0, CAT_CATEGORY_PROG},
670     {" edit list ", "list ", "Assistant creation de liste.", 0, 0, CAT_CATEGORY_LIST},
671     {" edit matrix ", "matrix ", "Assistant creation de matrice.", 0, 0, CAT_CATEGORY_MATRIX},
672     {" mksa(x)", 0, "Conversion en unites MKSA", 0, 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
673     {" ufactor(a,b)", 0, "Factorise l'unite b dans a", "100_J,1_kW", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
674     {" usimplify(a)", 0, "Simplifie l'unite dans a", "100_l/10_cm^2", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
675     //{"fonction def Xcas", "fonction f(x) local y;   ffonction:;", "Definition de fonction.", "#fonction f(x) local y; y:=x^2; return y; ffonction:;", 0, CAT_CATEGORY_PROG},
676     {"!", "!", "Non logique (prefixe) ou factorielle de n (suffixe).", "#7!", "#!b", CAT_CATEGORY_PROGCMD},
677     {"#", "#", "Commentaire Python, en Xcas taper //. Raccourci ALPHA F2", 0, 0, CAT_CATEGORY_PROG},
678     {"%", "%", "a % b signifie a modulo b", 0, 0, CAT_CATEGORY_ARIT | (CAT_CATEGORY_PROGCMD << 8)},
679     {"&", "&", "Et logique ou +", "#1&2", 0, CAT_CATEGORY_PROGCMD},
680     {":=", ":=", "Affectation vers la gauche (inverse de =>).", "#a:=3", 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)},
681     {"<", "<", "Inferieur strict. Raccourci SHIFT F2", 0, 0, CAT_CATEGORY_PROGCMD},
682     {"=>", "=>", "Affectation vers la droite ou conversion en (touche ->). Par exemple 5=>a ou x^4-1=>* ou (x+1)^2=>+ ou sin(x)^2=>cos.", "#5=>a", "#15_m=>_cm", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_PHYS <<8) | (CAT_CATEGORY_UNIT << 16)},
683     {">", ">", "Superieur strict. Raccourci F2.", 0, 0, CAT_CATEGORY_PROGCMD},
684     {"\\", "\\", "Caractere \\", 0, 0, CAT_CATEGORY_PROGCMD},
685     {"_", "_", "Caractere _. Prefixe d'unites.", 0, 0, CAT_CATEGORY_PROGCMD},
686     {"_(km/h)", "_(km/h)", "Vitesse en kilometre/heure", 0, 0, CAT_CATEGORY_UNIT},
687     {"_(m/s)", "_(m/s)", "Vitesse en metre/seconde", 0, 0, CAT_CATEGORY_UNIT},
688     {"_(m/s^2)", "_(m/s^2)", "Acceleration en metre par seconde au carre", 0, 0, CAT_CATEGORY_UNIT},
689     {"_(m^2/s)", "_(m^2/s)", "Viscosite", 0, 0, CAT_CATEGORY_UNIT},
690     {"_A", 0, "Intensite electrique en Ampere", 0, 0, CAT_CATEGORY_UNIT},
691     {"_Bq", 0, "Radioactivite: Becquerel", 0, 0, CAT_CATEGORY_UNIT},
692     {"_C", 0, "Charge electrique en Coulomb", 0, 0, CAT_CATEGORY_UNIT},
693     {"_Ci", 0, "Radioactivite: Curie", 0, 0, CAT_CATEGORY_UNIT},
694     {"_F", 0, "Farad", 0, 0, CAT_CATEGORY_UNIT},
695     {"_F_", 0, "constante de Faraday (charge globale d'une mole de charges élémentaires).", 0, 0, CAT_CATEGORY_PHYS},
696     {"_G_", 0, "constante de gravitation universelle. Force=_G_*m1*m2/r^2", 0, 0, CAT_CATEGORY_PHYS},
697     {"_H", 0, "Henry", 0, 0, CAT_CATEGORY_UNIT},
698     {"_Hz", 0, "Hertz", 0, 0, CAT_CATEGORY_UNIT},
699     {"_J", 0, "Energie en Joule=kg*m^2/s^2", 0, 0, CAT_CATEGORY_UNIT},
700     {"_K", 0, "Temperature en Kelvin", 0, 0, CAT_CATEGORY_UNIT},
701     {"_Kcal", 0, "Energie en kilo-calorier", 0, 0, CAT_CATEGORY_UNIT},
702     {"_MeV", 0, "Energie en mega-electron-Volt", 0, 0, CAT_CATEGORY_UNIT},
703     {"_N", 0, "Force en Newton=kg*m/s^2", 0, 0, CAT_CATEGORY_UNIT},
704     {"_NA_", 0, "Avogadro", 0, 0, CAT_CATEGORY_PHYS},
705     {"_Ohm", 0, "Resistance electrique en Ohm", 0, 0, CAT_CATEGORY_UNIT},
706     {"_PSun_", 0, "puissance du Soleil", 0, 0, CAT_CATEGORY_PHYS},
707     {"_Pa", 0, "Pression en Pascal=kg/m/s^2", 0, 0, CAT_CATEGORY_UNIT},
708     {"_REarth_", 0, "Rayon de la Terre", 0, 0, CAT_CATEGORY_PHYS},
709     {"_RSun_", 0, "rayon du Soleil", 0, 0, CAT_CATEGORY_PHYS},
710     {"_R_", 0, "constante des gaz (de Boltzmann par mole)", 0, 0, CAT_CATEGORY_PHYS},
711     {"_S", 0, "", 0, 0, CAT_CATEGORY_UNIT},
712     {"_StdP_", 0, "Pression standard (au niveau de la mer)", 0, 0, CAT_CATEGORY_PHYS},
713     {"_StdT_", 0, "temperature standard (0 degre Celsius exprimes en Kelvins)", 0, 0, CAT_CATEGORY_PHYS},
714     {"_Sv", 0, "Radioactivite: Sievert", 0, 0, CAT_CATEGORY_UNIT},
715     {"_T", 0, "Tesla", 0, 0, CAT_CATEGORY_UNIT},
716     {"_V", 0, "Tension electrique en Volt", 0, 0, CAT_CATEGORY_UNIT},
717     {"_Vm_", 0, "Volume molaire", 0, 0, CAT_CATEGORY_PHYS},
718     {"_W", 0, "Puissance en Watt=kg*m^2/s^3", 0, 0, CAT_CATEGORY_UNIT},
719     {"_Wb", 0, "Weber", 0, 0, CAT_CATEGORY_UNIT},
720     {"_alpha_", 0, "constante de structure fine", 0, 0, CAT_CATEGORY_PHYS},
721     {"_c_", 0, "vitesse de la lumiere", 0, 0, CAT_CATEGORY_PHYS},
722     {"_cd", 0, "Luminosite en candela", 0, 0, CAT_CATEGORY_UNIT},
723     {"_cdf", "_cdf", "Suffixe pour obtenir une distribution cumulee. Taper F2 pour la distribution cumulee inverse.", "#_icdf", 0, CAT_CATEGORY_PROBA},
724     {"_d", 0, "Temps: jour", 0, 0, CAT_CATEGORY_UNIT},
725     {"_deg", 0, "Angle en degres", 0, 0, CAT_CATEGORY_UNIT},
726     {"_eV", 0, "Energie en electron-Volt", 0, 0, CAT_CATEGORY_UNIT},
727     {"_epsilon0_", 0, "permittivite du vide", 0, 0, CAT_CATEGORY_PHYS},
728     {"_ft", 0, "Longueur en pieds", 0, 0, CAT_CATEGORY_UNIT},
729     {"_g_", 0, "gravite au sol", 0, 0, CAT_CATEGORY_PHYS},
730     {"_grad", 0, "Angle en grades", 0, 0, CAT_CATEGORY_UNIT},
731     {"_h", 0, "Heure", 0, 0, CAT_CATEGORY_UNIT},
732     {"_h_", 0, "constante de Planck", 0, 0, CAT_CATEGORY_PHYS},
733     {"_ha", 0, "Aire en hectare", 0, 0, CAT_CATEGORY_UNIT},
734     {"_hbar_", 0, "constante de Planck/(2*pi)", 0, 0, CAT_CATEGORY_PHYS},
735     {"_inch", 0, "Longueur en pouces", 0, 0, CAT_CATEGORY_UNIT},
736     {"_kWh", 0, "Energie en kWh", 0, 0, CAT_CATEGORY_UNIT},
737     {"_k_", 0, "constante de Boltzmann", 0, 0, CAT_CATEGORY_PHYS},
738     {"_kg", 0, "Masse en kilogramme", 0, 0, CAT_CATEGORY_UNIT},
739     {"_l", 0, "Volume en litre", 0, 0, CAT_CATEGORY_UNIT},
740     {"_m", 0, "Longueur en metre", 0, 0, CAT_CATEGORY_UNIT},
741     {"_mEarth_", 0, "masse de la Terre", 0, 0, CAT_CATEGORY_PHYS},
742     {"_m^2", 0, "Aire en m^2", 0, 0, CAT_CATEGORY_UNIT},
743     {"_m^3", 0, "Volume en m^3", 0, 0, CAT_CATEGORY_UNIT},
744     {"_me_", 0, "masse electron", 0, 0, CAT_CATEGORY_PHYS},
745     {"_miUS", 0, "Longueur en miles US", 0, 0, CAT_CATEGORY_UNIT},
746     {"_mn", 0, "Temps: minute", 0, 0, CAT_CATEGORY_UNIT},
747     {"_mp_", 0, "masse proton", 0, 0, CAT_CATEGORY_PHYS},
748     {"_mpme_", 0, "ratio de masse proton/electron", 0, 0, CAT_CATEGORY_PHYS},
749     {"_mu0_", 0, "permeabilite du vide", 0, 0, CAT_CATEGORY_PHYS},
750     {"_phi_", 0, "quantum flux magnetique", 0, 0, CAT_CATEGORY_PHYS},
751     {"_plot", "_plot", "Suffixe pour obtenir le graphe d'une regression.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
752     {"_qe_", 0, "charge de l'electron", 0, 0, CAT_CATEGORY_PHYS},
753     {"_qme_", 0, "_q_/_me_", 0, 0, CAT_CATEGORY_PHYS},
754     {"_rad", 0, "Angle en radians", 0, 0, CAT_CATEGORY_UNIT},
755     {"_rem", 0, "Radioactivite: rem", 0, 0, CAT_CATEGORY_UNIT},
756     {"_s", 0, "Temps: seconde", 0, 0, CAT_CATEGORY_UNIT},
757     {"_sd_", 0, "Jour sideral", 0, 0, CAT_CATEGORY_PHYS},
758     {"_syr_", 0, "Annee siderale", 0, 0, CAT_CATEGORY_PHYS},
759     {"_tr", 0, "Angle en tours", 0, 0, CAT_CATEGORY_UNIT},
760     {"_yd", 0, "Longueur en yards", 0, 0, CAT_CATEGORY_UNIT},
761     {"a and b", " and ", "Et logique", 0, 0, CAT_CATEGORY_PROGCMD},
762     {"a or b", " or ", "Ou logique", 0, 0, CAT_CATEGORY_PROGCMD},
763     {"abcuv(a,b,c)", 0, "Cherche 2 polynomes u,v tels que a*u+b*v=c","x+1,x^2-2,x", 0, CAT_CATEGORY_POLYNOMIAL},
764     {"abs(x)", 0, "Valeur absolue, module ou norme de x", "-3", "[1,2,3]", CAT_CATEGORY_COMPLEXNUM | (CAT_CATEGORY_REAL<<8)},
765     {"append", 0, "Ajoute un element en fin de liste l","#l.append(x)", 0, CAT_CATEGORY_LIST},
766     {"approx(x)", 0, "Valeur approchee de x. Raccourci S-D", "pi", 0, CAT_CATEGORY_REAL},
767     {"arg(z)", 0, "Argument du complexe z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
768     {"asc(string)", 0, "Liste des codes ASCII d'une chaine", "\"Bonjour\"", 0, CAT_CATEGORY_ARIT},
769     {"assume(hyp)", 0, "Hypothese sur une variable.", "x>1", "x>-1 and x<1", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_SOFUS<<8)},
770     {"avance n", "avance ", "La tortue avance de n pas, par defaut n=10", "#avance 40", 0, CAT_CATEGORY_LOGO},
771     {"axes", "axes", "Axes visibles ou non axes=1 ou 0", "#axes=0", "#axes=1", CAT_CATEGORY_PROGCMD << 8},
772     {"baisse_crayon ", "baisse_crayon ", "La tortue se deplace en marquant son passage.", 0, 0, CAT_CATEGORY_LOGO},
773     {"barplot(list)", 0, "Diagramme en batons d'une serie statistique 1d.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
774     {"binomial(n,p,k)", 0, "binomial(n,p,k) probabilite de k succes avec n essais ou p est la proba de succes d'un essai. binomial_cdf(n,p,k) est la probabilite d'obtenir au plus k succes avec n essais. binomial_icdf(n,p,t) renvoie le plus petit k tel que binomial_cdf(n,p,k)>=t", "10,.5,4", 0, CAT_CATEGORY_PROBA},
775     {"bitxor", "bitxor", "Ou exclusif", "#bitxor(1,2)", 0, CAT_CATEGORY_PROGCMD},
776     {"black", "black", "Option d'affichage", "#display=black", 0, CAT_CATEGORY_PROGCMD},
777     {"blue", "blue", "Option d'affichage", "#display=blue", 0, CAT_CATEGORY_PROGCMD},
778     {"cache_tortue ", "cache_tortue ", "Cache la tortue apres avoir trace le dessin.", 0, 0, CAT_CATEGORY_LOGO},
779     {"camembert(list)", 0, "Diagramme en camembert d'une serie statistique 1d.", "[[\"France\",6],[\"Allemagne\",12],[\"Suisse\",5]]", 0, CAT_CATEGORY_STATS},
780     {"ceiling(x)", 0, "Partie entiere superieure", "1.2", 0, CAT_CATEGORY_REAL},
781     {"cercle(centre,rayon)", 0, "Cercle donne par centre et rayon ou par un diametre", "2+i,3", "1-i,1+i", CAT_CATEGORY_PROGCMD},
782     {"cfactor(p)", 0, "Factorisation sur C.", "x^4-1", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)},
783     {"char(liste)", 0, "Chaine donnee par une liste de code ASCII", "[97,98,99]", 0, CAT_CATEGORY_ARIT},
784     {"charpoly(M,x)", 0, "Polynome caracteristique de la matrice M en la variable x.", "[[1,2],[3,4]],x", 0, CAT_CATEGORY_MATRIX},
785     {"clearscreen()", "clearscreen()", "Efface l'ecran.", 0, 0, CAT_CATEGORY_PROGCMD},
786     {"coeff(p,x,n)", 0, "Coefficient de x^n dans le polynome p.", "(1+x)^6,x,3", 0, CAT_CATEGORY_POLYNOMIAL},
787     {"comb(n,k)", 0, "Renvoie k parmi n.", "10,4", 0, CAT_CATEGORY_PROBA},
788     {"cond(A,[1,2,inf])", 0, "Nombre de condition d'une matrice par rapport a la norme specifiee (par defaut 1)", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
789     {"conj(z)", 0, "Conjugue complexe de z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
790     {"correlation(l1,l2)", 0, "Correlation listes l1 et l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
791     {"covariance(l1,l2)", 0, "Covariance listes l1 et l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
792     {"cpartfrac(p,x)", 0, "Decomposition en elements simples sur C.", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)},
793     {"crayon ", "crayon ", "Couleur de trace de la tortue", "#crayon rouge", 0, CAT_CATEGORY_LOGO},
794     {"cross(u,v)", 0, "Produit vectoriel de u et v.","[1,2,3],[0,1,3]", 0, CAT_CATEGORY_LINALG},
795     {"csolve(equation,x)", 0, "Resolution exacte dans C d'une equation en x (ou d'un systeme polynomial).","x^2+x+1=0", 0, CAT_CATEGORY_SOLVE | (CAT_CATEGORY_COMPLEXNUM << 8)},
796     {"curl(u,vars)", 0, "Rotationnel du vecteur u.", "[2*x*y,x*z,y*z],[x,y,z]", 0, CAT_CATEGORY_LINALG},
797     {"cyan", "cyan", "Option d'affichage", "#display=cyan", 0, CAT_CATEGORY_PROGCMD},
798     {"debug(f(args))", 0, "Execute la fonction f en mode pas a pas.", 0, 0, CAT_CATEGORY_PROG},
799     {"degree(p,x)", 0, "Degre du polynome p en x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL},
800     {"denom(x)", 0, "Denominateur de l'expression x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL},
801     {"desolve(equation,t,y)", 0, "Resolution exacte d'equation differentielle ou de systeme differentiel lineaire a coefficients constants.", "[y'+y=exp(x),y(0)=1]", "[y'=[[1,2],[2,1]]*y+[x,x+1],y(0)=[1,2]]", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_CALCULUS << 8)},
802     {"det(A)", 0, "Determinant de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
803     {"diff(f,var,[n])", 0, "Derivee de l'expression f par rapport a var (a l'ordre n, n=1 par defaut), par exemple diff(sin(x),x) ou diff(x^3,x,2). Pour deriver f par rapport a x, utiliser f' (raccourci F3). Pour le gradient de f, var est la liste des variables.", "sin(x),x", "sin(x^2),x,3", CAT_CATEGORY_CALCULUS},
804     {"display", "display", "Option d'affichage", "#display=red", 0, CAT_CATEGORY_PROGCMD},
805     {"disque n", "disque ", "Cercle rempli tangent a la tortue, de rayon n. Utiliser disque n,theta pour remplir un morceau de camembert ou disque n,theta,segment pour remplir un segment de disque", "#disque 30", "#disque(30,90)", CAT_CATEGORY_LOGO},
806     {"dot(a,b)", 0, "Produit scalaire de 2 vecteurs. Raccourci: *", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_LINALG},
807     {"draw_arc(x1,y1,rx,ry,theta1,theta2,c)", 0, "Arc d'ellipse pixelise.", "100,100,60,80,0,pi,magenta", 0, CAT_CATEGORY_PROGCMD},
808     {"draw_circle(x1,y1,r,c)", 0, "Cercle pixelise. Option filled pour le remplir.", "100,100,60,cyan+filled", 0, CAT_CATEGORY_PROGCMD},
809     {"draw_line(x1,y1,x2,y2,c)", 0, "Droite pixelisee.", "100,50,300,200,blue", 0, CAT_CATEGORY_PROGCMD},
810     {"draw_pixel(x,y,color)", 0, "Colorie le pixel x,y. Faire draw_pixel() pour synchroniser l'ecran.", 0, 0, CAT_CATEGORY_PROGCMD},
811     {"draw_polygon([[x1,y1],...],c)", 0, "Polygone pixelise.", "[[100,50],[30,20],[60,70]],red+filled", 0, CAT_CATEGORY_PROGCMD},
812     {"draw_rectangle(x,y,w,h,c)", 0, "Rectangle pixelise.", "100,50,30,20,red+filled", 0, CAT_CATEGORY_PROGCMD},
813     {"draw_string(s,x,y,c)", 0, "Affiche la chaine s en x,y", "\"Bonjour\",80,60", 0, CAT_CATEGORY_PROGCMD},
814     {"droite(equation)", 0, "Droite donnee par une equation ou 2 points", "y=2x+1", "1+i,2-i", CAT_CATEGORY_PROGCMD},
815     {"ecris ", "ecris ", "Ecrire a la position de la tortue", "#ecris \"coucou\"", 0, CAT_CATEGORY_LOGO},
816     {"efface", "efface", "Remise a zero de la tortue", 0, 0, CAT_CATEGORY_LOGO},
817     {"egcd(A,B)", 0, "Cherche des polynomes U,V,D tels que A*U+B*V=D=gcd(A,B)","x^2+3x+1,x^2-5x-1", 0, CAT_CATEGORY_POLYNOMIAL},
818     {"eigenvals(A)", 0, "Valeurs propres de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
819     {"eigenvects(A)", 0, "Vecteurs propres de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
820     {"elif (test)", "elif", "Tests en cascade", 0, 0, CAT_CATEGORY_PROG},
821 				     //{"end", "end", "Fin de bloc", 0, 0, CAT_CATEGORY_PROG},
822     {"erf(x)", 0, "Fonction erreur en x.", "1.2", 0, CAT_CATEGORY_PROBA},
823     {"erfc(x)", 0, "Fonction erreur complementaire en x.", "1.2", 0, CAT_CATEGORY_PROBA},
824     {"euler(n)",0,"Indicatrice d'Euler: nombre d'entiers < n premiers avec n","25",0,CAT_CATEGORY_ARIT},
825     {"eval(f)", 0, "Evalue f.", 0, 0, CAT_CATEGORY_PROGCMD},
826     {"evalc(z)", 0, "Ecrit z=x+i*y.", "1/(1+i*sqrt(3))", 0, CAT_CATEGORY_COMPLEXNUM},
827     {"exact(x)", 0, "Convertit x en rationnel. Raccourci shift S-D", "1.2", 0, CAT_CATEGORY_REAL},
828     {"exp2trig(expr)", 0, "Conversion d'exponentielles complexes en sin/cos", "exp(i*x)", 0, CAT_CATEGORY_TRIG},
829     {"exponential_regression(Xlist,Ylist)", 0, "Regression exponentielle.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
830     {"exponential_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression exponentielle.", "#X,Y:=[1,2,3,4,5],[1,3,4,6,8];exponential_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS},
831     {"exponentiald(lambda,x)", 0, "Loi exponentielle de parametre lambda. exponentiald_cdf(lambda,x) probabilite que \"loi exponentielle <=x\" par ex. exponentiald_cdf(2,3). exponentiald_icdf(lambda,t) renvoie x tel que \"loi exponentielle <=x\" vaut t, par ex. exponentiald_icdf(2,0.95) ", "5.1,3.4", 0, CAT_CATEGORY_PROBA},
832     {"extend", 0, "Concatene 2 listes. Attention a ne pas utiliser + qui effectue l'addition de 2 vecteurs.","#l1.extend(l2)", 0, CAT_CATEGORY_LIST},
833     {"factor(p,[x])", 0, "Factorisation du polynome p (utiliser ifactor pour un entier). Raccourci: p=>*", "x^4-1", "x^6+1,sqrt(3)", CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_POLYNOMIAL << 8)},
834     {"filled", "filled", "Option d'affichage", 0, 0, CAT_CATEGORY_PROGCMD},
835     {"float(x)", 0, "Convertit x en nombre approche (flottant).", "pi", 0, CAT_CATEGORY_REAL},
836     {"floor(x)", 0, "Partie entiere de x", "pi", 0, CAT_CATEGORY_REAL},
837     {"fonction f(x)", "fonction", "Definition de fonction (Xcas). Par exemple\nfonction f(x)\n local y;\ny:=x*x;\nreturn y;\nffonction", 0, 0, CAT_CATEGORY_PROG},
838     {"from math/... import *", "from math import *", "Instruction pour utiliser les fonctions de maths ou des fonctions aleatoires [random] ou la tortue en anglais [turtle]. Importer math n'est pas necessaire dans KhiCAS", "#from random import *", "#from turtle import *", CAT_CATEGORY_PROG},
839     {"fsolve(equation,x=a[..b])", 0, "Resolution approchee de equation pour x dans l'intervalle a..b ou en partant de x=a.","cos(x)=x,x=0..1", "cos(x)-x,x=0.0", CAT_CATEGORY_SOLVE},
840     {"gauss(q)", 0, "Reduction de Gauss d'une forme quadratique q", "x^2+x*y+x*z,[x,y,z]", "x^2+4*x*y,[]", CAT_CATEGORY_LINALG },
841     {"gcd(a,b,...)", 0, "Plus grand commun diviseur. Voir iegcd ou egcd pour Bezout.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)},
842     {"gl_x", "gl_x", "Reglage graphique X gl_x=xmin..xmax", "#gl_x=0..2", 0, CAT_CATEGORY_PROGCMD << 8},
843     {"gl_y", "gl_y", "Reglage graphique Y gl_y=ymin..ymax", "#gl_y=-1..1", 0, CAT_CATEGORY_PROGCMD << 8},
844     {"green", "green", "Option d'affichage", "#display=green", 0, CAT_CATEGORY_PROGCMD},
845     {"halftan(expr)", 0, "Exprime cos, sin, tan avec tan(angle/2).","cos(x)", 0, CAT_CATEGORY_TRIG},
846     {"hermite(n)", 0, "n-ieme polynome de Hermite", "10", "10,t", CAT_CATEGORY_POLYNOMIAL},
847     {"hilbert(n)", 0, "Matrice de Hilbert de taille n.", "4", 0, CAT_CATEGORY_MATRIX},
848     {"histogram(list,min,size)", 0, "Histogramme d'une liste de donneees, classes commencant a min de taille size.","ranv(100,uniformd,0,1),0,0.1", 0, CAT_CATEGORY_STATS},
849     {"iabcuv(a,b,c)", 0, "Cherche 2 entiers u,v tels que a*u+b*v=c","23,13,15", 0, CAT_CATEGORY_ARIT},
850     {"ichinrem([a,m],[b,n])", 0,"Restes chinois entiers de a mod m et b mod n.", "[3,13],[2,7]", 0, CAT_CATEGORY_ARIT},
851     {"idivis(n)", 0, "Liste des diviseurs d'un entier n.", "10", 0, CAT_CATEGORY_ARIT},
852     {"idn(n)", 0, "matrice identite n * n", "4", 0, CAT_CATEGORY_MATRIX},
853     {"iegcd(a,b)", 0, "Determine les entiers u,v,d tels que a*u+b*v=d=gcd(a,b)","23,13", 0, CAT_CATEGORY_ARIT},
854     {"ifactor(n)", 0, "Factorisation d'un entier (pas trop grand!). Raccourci n=>*", "1234", 0, CAT_CATEGORY_ARIT},
855     {"ilaplace(f,s,x)", 0, "Transformee inverse de Laplace de f", "s/(s^2+1),s,x", 0, CAT_CATEGORY_CALCULUS},
856     {"im(z)", 0, "Partie imaginaire.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
857     {"inf", "inf", "Plus l'infini. Utiliser -inf pour moins l'infini ou infinity pour l'infini complexe. Raccourci shift INS.", "-inf", "infinity", CAT_CATEGORY_CALCULUS},
858     {"input()", "input()", "Lire une chaine au clavier", "\"Valeur ?\"", 0, CAT_CATEGORY_PROG},
859     {"integrate(f,x,[,a,b])", 0, "Primitive de f par rapport a la variable x, par ex. integrate(x*sin(x),x). Pour calculer une integrale definie, entrer les arguments optionnels a et b, par ex. integrate(x*sin(x),x,0,pi). Raccourci SHIFT F3.", "x*sin(x),x", "cos(x)/(1+x^4),x,0,inf", CAT_CATEGORY_CALCULUS},
860     {"interp(X,Y[,interp])", 0, "Interpolation de Lagrange aux points (xi,yi) avec X la liste des xi et Y des yi. Renvoie la liste des differences divisees si interp est passe en parametre.", "[1,2,3,4,5],[0,1,3,4,4]", "[1,2,3,4,5],[0,1,3,4,4],interp", CAT_CATEGORY_POLYNOMIAL},
861     {"inv(A)", 0, "Inverse de A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
862     {"inverser(v)", "inverser ", "La variable v est remplacee par son inverse", "#v:=3; inverser v", 0, CAT_CATEGORY_SOFUS},
863     {"iquo(a,b)", 0, "Quotient euclidien de deux entiers.", "23,13", 0, CAT_CATEGORY_ARIT},
864     {"irem(a,b)", 0,"Reste euclidien de deux entiers", "23,13", 0, CAT_CATEGORY_ARIT},
865     {"isprime(n)", 0, "Renvoie 1 si n est premier, 0 sinon.", "11", "10", CAT_CATEGORY_ARIT},
866     {"jordan(A)", 0, "Forme normale de Jordan de la matrice A, renvoie P et D tels que P^-1*A*P=D", "[[1,2],[3,4]]", "[[1,1,-1,2,-1],[2,0,1,-4,-1],[0,1,1,1,1],[0,1,2,0,1],[0,0,-3,3,-1]]", CAT_CATEGORY_MATRIX},
867     {"laguerre(n,a,x)", 0, "n-ieme polynome de Laguerre (a=0 par defaut).", "10", 0, CAT_CATEGORY_POLYNOMIAL},
868     {"laplace(f,x,s)", 0, "Transformee de Laplace de f","sin(x),x,s", 0, CAT_CATEGORY_CALCULUS},
869     {"lcm(a,b,...)", 0, "Plus petit commun multiple.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)},
870     {"lcoeff(p,x)", 0, "Coefficient dominant du polynome p.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL},
871     {"legendre(n)", 0, "n-ieme polynome de Legendre.", "10", "10,t", CAT_CATEGORY_POLYNOMIAL},
872 #ifdef RELEASE
873     {"len(l)", 0, "Taille d'une liste.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_LIST},
874 #endif
875     {"leve_crayon ", "leve_crayon ", "La tortue se deplace sans marquer son passage", 0, 0, CAT_CATEGORY_LOGO},
876     {"limit(f,x=a)", 0, "Limite de f en x = a. Ajouter 1 ou -1 pour une limite a droite ou a gauche, limit(sin(x)/x,x=0) ou limit(abs(x)/x,x=0,1). Raccourci: SHIFT MIXEDFRAC", "sin(x)/x,x=0", "exp(-1/x),x=0,1", CAT_CATEGORY_CALCULUS},
877     {"line_width_", "line_width_", "Prefixe d'epaisseur (2 a 8)", 0, 0, CAT_CATEGORY_PROGCMD},
878     {"linear_regression(Xlist,Ylist)", 0, "Regression lineaire.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
879     {"linear_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression lineaire.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];linear_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS },
880     {"linetan(expr,x,x0)", 0, "Tangente au graphe en x=x0.", "sin(x),x,pi/2", 0, CAT_CATEGORY_PLOT},
881     {"linsolve([eq1,eq2,..],[x,y,..])", 0, "Resolution de systeme lineaire. Peut utiliser le resultat de lu pour resolution en O(n^2).","[x+y=1,x-y=2],[x,y]", "#p,l,u:=lu([[1,2],[3,4]]); linsolve(p,l,u,[5,6])", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_LINALG <<8) | (CAT_CATEGORY_MATRIX << 16)},
882     {"logarithmic_regression(Xlist,Ylist)", 0, "Regression logarithmique.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
883     {"logarithmic_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression logarithmique.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];logarithmic_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS},
884     {"lu(A)", 0, "decomposition LU de la matrice A, P*A=L*U, renvoie P permutation, L et U triangulaires inferieure et superieure", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
885     {"magenta", "magenta", "Option d'affichage", "#display=magenta", 0, CAT_CATEGORY_PROGCMD},
886     {"map(l,f)", 0, "Applique f aux elements de la liste l.","[1,2,3],x->x^2", 0, CAT_CATEGORY_LIST},
887     {"matpow(A,n)", 0, "Renvoie A^n, la matrice A la puissance n", "[[1,2],[3,4]],n","#assume(n>=1);matpow([[0,2],[0,4]],n)", CAT_CATEGORY_MATRIX},
888     {"matrix(l,c,func)", 0, "Matrice de terme general donne.", "2,3,(j,k)->j^k", 0, CAT_CATEGORY_MATRIX},
889     {"mean(l)", 0, "Moyenne arithmetique liste l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
890     {"median(l)", 0, "Mediane", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
891     {"montre_tortue ", "montre_tortue ", "Affiche la tortue", 0, 0, CAT_CATEGORY_LOGO},
892     {"mult_c_conjugate", 0, "Multiplier par le conjugue complexe.", "1+2*i", 0,  (CAT_CATEGORY_COMPLEXNUM << 8)},
893     {"mult_conjugate", 0, "Multiplier par le conjugue (sqrt).", "sqrt(2)-sqrt(3)", 0, CAT_CATEGORY_ALGEBRA},
894     {"normald([mu,sigma],x)", 0, "Loi normale, par defaut mu=0 et sigma=1. normald_cdf([mu,sigma],x) probabilite que \"loi normale <=x\" par ex. normald_cdf(1.96). normald_icdf([mu,sigma],t) renvoie x tel que \"loi normale <=x\" vaut t, par ex. normald_icdf(0.975) ", "1.2", 0, CAT_CATEGORY_PROBA},
895     {"not(x)", 0, "Non logique.", 0, 0, CAT_CATEGORY_PROGCMD},
896     {"numer(x)", 0, "Numerateur de x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL},
897     {"odesolve(f(t,y),[t,y],[t0,y0],t1)", 0, "Solution approchee d'equation differentielle y'=f(t,y) et y(t0)=y0, valeur en t1 (ajouter curve pour les valeurs intermediaires de y)", "sin(t*y),[t,y],[0,1],2", "0..pi,(t,v)->{[-v[1],v[0]]},[0,1]", CAT_CATEGORY_SOLVE},
898     {"partfrac(p,x)", 0, "Decomposition en elements simples. Raccourci p=>+", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA},
899     {"pas_de_cote n", "pas_de_cote ", "Saut lateral de la tortue, par defaut n=10", "#pas_de_cote 30", 0, CAT_CATEGORY_LOGO},
900     {"plot(expr,x)", 0, "Graphe de fonction. Par exemple plot(sin(x)), plot(ln(x),x.0,5)", "ln(x),x=0..5", "1/x,x=1..5,xstep=1", CAT_CATEGORY_PLOT},
901     {"plotarea(expr,x=a..b,[n,meth])", 0, "Aire sous la courbe selon une methode d'integration.", "1/x,x=1..5,4,rectangle_gauche", 0, CAT_CATEGORY_PLOT},
902     {"plotcontour(expr,[x=xm..xM,y=ym..yM],niveaux)", 0, "Lignes de niveau de expr.", "x^2+2y^2, [x=-2..2,y=-2..2],[1,2]", 0, CAT_CATEGORY_PLOT},
903     {"plotdensity(expr,[x=xm..xM,y=ym..yM])", 0, "Representation en niveaux de couleurs d'une expression de 2 variables.", "x^2-y^2,[x=-3..3,y=-2..2]", 0, CAT_CATEGORY_PLOT},
904     {"plotfield(f(t,y), [t=tmin..tmax,y=ymin..ymax])", 0, "Champ des tangentes de y'=f(t,y), optionnellement graphe avec plotode=[t0,y0]", "sin(t*y), [t=-3..3,y=-3..3],plotode=[0,1]", "5*[-y,x], [x=-1..1,y=-1..1]", CAT_CATEGORY_PLOT},
905     {"plotlist(list)", 0, "Graphe d'une liste", "[3/2,2,1,1/2,3,2,3/2]", "[1,13],[2,10],[3,15],[4,16]", CAT_CATEGORY_PLOT},
906     {"plotode(f(t,y), [t=tmin..tmax,y],[t0,y0])", 0, "Graphe de solution d'equation differentielle y'=f(t,y), y(t0)=y0.", "sin(t*y),[t=-3..3,y],[0,1]", 0, CAT_CATEGORY_PLOT},
907     {"plotparam([x,y],t)", 0, "Graphe en parametriques. Par exemple plotparam([sin(3t),cos(2t)],t,0,pi) ou plotparam(exp(i*t),t,0,pi)", "[sin(3t),cos(2t)],t,0,pi", "[t^2,t^3],t=-1..1,tstep=0.1", CAT_CATEGORY_PLOT},
908     {"plotpolar(r,theta)", 0, "Graphe en polaire.","cos(3*x),x,0,pi", "1/(1+cos(x)),x=0..pi,xstep=0.05", CAT_CATEGORY_PLOT},
909     {"plotseq(f(x),x=[u0,m,M],n)", 0, "Trace f(x) sur [m,M] et n termes de la suite recurrente u_{n+1}=f(u_n) de 1er terme u0.","sqrt(2+x),x=[6,0,7],5", 0, CAT_CATEGORY_PLOT},
910     {"plus_point", "plus_point", "Option d'affichage", "#display=blue+plus_point", 0, CAT_CATEGORY_PROGCMD },
911     {"point(x,y)", 0, "Point", "1,2", 0, CAT_CATEGORY_PROGCMD},
912     {"polygon(list)", 0, "Polygone ferme.", "1-i,2+i,3", 0, CAT_CATEGORY_PROGCMD},
913     {"polygonscatterplot(Xlist,Ylist)", 0, "Nuage de points relies.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
914     {"polynomial_regression(Xlist,Ylist,n)", 0, "Regression polynomiale de degre <= n.", "[1,2,3,4,5],[0,1,3,4,4],2", 0, CAT_CATEGORY_STATS},
915     {"polynomial_regression_plot(Xlist,Ylist,n)", 0, "Graphe d'une regression polynomiale de degre <= n.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y);", 0, CAT_CATEGORY_STATS},
916     {"pour (boucle Xcas)", "pour  de  to  faire  fpour;", "Boucle definie.","#pour j de 1 to 10 faire print(j,j^2); fpour;", 0, CAT_CATEGORY_PROG},
917     {"power_regression(Xlist,Ylist,n)", 0, "Regression puissance.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
918     {"power_regression_plot(Xlist,Ylist,n)", 0, "Graphe d'une regression puissance.", "#X,Y:=[1,2,3,4,5],[1,1,3,4,4];power_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS},
919     {"powmod(a,n,p[,P,x])", 0, "Renvoie a^n mod p, ou a^n mod un entier p et un polynome P en x.","123,456,789", "x+1,452,19,x^4+x+1,x", CAT_CATEGORY_ARIT},
920     {"print(expr)", 0, "Afficher dans la console", 0, 0, CAT_CATEGORY_PROG},
921     {"proot(p)", 0, "Racines reelles et complexes approchees d'un polynome. Exemple proot([1,2.1,3,4.2]) ou proot(x^3+2.1*x^2+3x+4.2)", "x^3+2.1*x^2+3x+4.2", 0, CAT_CATEGORY_POLYNOMIAL},
922     {"purge(x)", 0, "Purge le contenu de la variable x. Raccourci SHIFT-FORMAT", 0, 0, CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_SOFUS<<8)},
923     {"python(f)", 0, "Affiche la fonction f en syntaxe Python.", 0, 0, CAT_CATEGORY_PROGCMD},
924     {"python_compat(0|1|2)", 0, "python_compat(0) syntaxe Xcas, python_compat(1) syntaxe Python avec ^ interprete comme puissance, python_compat(2) ^ interprete comme ou exclusif bit a bit", "0", "1", CAT_CATEGORY_PROG},
925     {"qr(A)", 0, "Factorisation A=Q*R avec Q orthogonale et R triangulaire superieure", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
926     {"quartile1(l)", 0, "1er quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
927     {"quartile3(l)", 0, "3eme quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
928     {"quo(p,q,x)", 0, "Quotient de division euclidienne polynomiale en x.", 0, 0, CAT_CATEGORY_POLYNOMIAL},
929     {"quote(x)", 0, "Renvoie l'expression x non evaluee.", 0, 0, CAT_CATEGORY_ALGEBRA},
930     {"rand()", "rand()", "Reel aleatoire entre 0 et 1", 0, 0, CAT_CATEGORY_PROBA},
931     {"randint(n)", 0, "Entier aleatoire entre 1 et n ou entre a et b si on fournit 2 arguments", "6", "5,20", CAT_CATEGORY_PROBA},
932     {"ranm(n,m,[loi,parametres])", 0, "Matrice aleatoire a coefficients entiers ou selon une loi de probabilites (ranv pour un vecteur). Exemples ranm(2,3), ranm(3,2,binomial,20,.3), ranm(4,2,normald,0,1)", "4,2,normald,0,1", "3,3,10", CAT_CATEGORY_MATRIX},
933     {"ranv(n,[loi,parametres])", 0, "Vecteur aleatoire", "4,normald,0,1", "10,30", CAT_CATEGORY_LINALG},
934     {"ratnormal(x)", 0, "Ecrit sous forme d'une fraction irreductible.", "(x+1)/(x^2-1)^2", 0, CAT_CATEGORY_ALGEBRA},
935     {"re(z)", 0, "Partie reelle.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
936     {"read(\"filename\")", "read(\"", "Lire un fichier. Voir aussi write", 0, 0, CAT_CATEGORY_PROGCMD},
937     {"rectangle_plein a,b", "rectangle_plein ", "Rectangle direct rempli depuis la tortue de cotes a et b (si b est omis, la tortue remplit un carre)", "#rectangle_plein 30", "#rectangle_plein(20,40)", CAT_CATEGORY_LOGO},
938     {"recule n", "recule ", "La tortue recule de n pas, par defaut n=10", "#recule 30", 0, CAT_CATEGORY_LOGO},
939     {"red", "red", "Option d'affichage", "#display=red", 0, CAT_CATEGORY_PROGCMD},
940     {"rem(p,q,x)", 0, "Reste de division euclidienne polynomiale en x", 0, 0, CAT_CATEGORY_POLYNOMIAL},
941     {"repete(n,...)", "repete( ", "Repete plusieurs fois les instructions", "#repete(4,avance,tourne_gauche)", 0, CAT_CATEGORY_LOGO},
942 #ifdef RELEASE
943     {"residue(f(z),z,z0)", 0, "Residu de l'expression en z0.", "1/(x^2+1),x,i", 0, CAT_CATEGORY_COMPLEXNUM},
944 #endif
945     {"resultant(p,q,x)", 0, "Resultant en x des polynomes p et q.", "#P:=x^3+p*x+q;resultant(P,P',x);", 0, CAT_CATEGORY_POLYNOMIAL},
946     {"revert(p[,x])", 0, "Developpement de Taylor reciproque, p doit etre nul en 0","x+x^2+x^4", 0, CAT_CATEGORY_CALCULUS},
947     {"rgb(r,g,b)", 0, "couleur definie par niveau de rouge, vert, bleu entre 0 et 255", "255,0,255", 0, CAT_CATEGORY_PROGCMD},
948     {"rhombus_point", "rhombus_point", "Option d'affichage", "#display=magenta+rhombus_point", 0, CAT_CATEGORY_PROGCMD },
949     {"rond n", "rond ", "Cercle tangent a la tortue de rayon n. Utiliser rond n,theta pour un arc de cercle.", "#rond 30", "#rond(30,90)", CAT_CATEGORY_LOGO},
950     {"rsolve(equation,u(n),[init])", 0, "Expression d'une suite donnee par une recurrence.","u(n+1)=2*u(n)+3,u(n),u(0)=1", "([u(n+1)=3*v(n)+u(n),v(n+1)=v(n)+u(n)],[u(n),v(n)],[u(0)=1,v(0)=2]", CAT_CATEGORY_SOLVE},
951     {"saute n", "saute ", "La tortue fait un saut de n pas, par defaut n=10", "#saute 30", 0, CAT_CATEGORY_LOGO},
952     {"scatterplot(Xlist,Ylist)", 0, "Nuage de points.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
953     {"segment(A,B)", 0, "Segment", "1,2+i", 0, CAT_CATEGORY_PROGCMD},
954     {"seq(expr,var,a,b[,pas])", 0, "Liste de terme general donne.","j^2,j,1,10", "j^2,j,1,10,2", CAT_CATEGORY_LIST},
955     {"si (test Xcas)", "si  alors  sinon  fsi;", "Test.", "#f(x):=si x>0 alors x; sinon -x; fsi;", 0, CAT_CATEGORY_PROG},
956     {"sign(x)", 0, "Renvoie -1 si x est negatif, 0 si x est nul et 1 si x est positif.", 0, 0, CAT_CATEGORY_REAL},
957     {"simplify(expr)", 0, "Renvoie en general expr sous forme simplifiee. Raccourci expr=>/", "sin(3x)/sin(x)", "ln(4)-ln(2)", CAT_CATEGORY_ALGEBRA},
958     {"sin_regression(Xlist,Ylist)", 0, "Regression trigonometrique.", "[1,2,3,4,5,6,7,8,9,10,11,12,13,14],[0.1,0.5,0.8,1,0.7,0.5,0.05,-.5,-.75,-1,-.7,-.4,0.1,.5]", 0, CAT_CATEGORY_STATS},
959     {"sin_regression_plot(Xlist,Ylist)", 0, "Graphe d'une regression trigonometrique.", "#X,Y:=[1,2,3,4,5,6,7,8,9,10,11,12,13,14],[0.1,0.5,0.8,1,0.7,0.5,0.05,-.5,-.75,-1,-.7,-.4,0.1,.5];sin_regression_plot(X,Y);", 0, CAT_CATEGORY_STATS },
960     {"solve(equation,x)", 0, "Resolution exacte d'une equation en x (ou d'un systeme polynomial). Utiliser csolve pour les solutions complexes, linsolve pour un systeme lineaire. Raccourci SHIFT XthetaT", "x^2-x-1=0,x", "[x^2-y^2=0,x^2-z^2=0],[x,y,z]", CAT_CATEGORY_SOLVE},
961     {"sort(l)", 0, "Trie une liste.","[3/2,2,1,1/2,3,2,3/2]", "[[1,2],[2,3],[4,3]],(x,y)->when(x[1]==y[1],x[0]>y[0],x[1]>y[1]", CAT_CATEGORY_LIST},
962     {"square_point", "square_point", "Option d'affichage", "#display=cyan+square_point", 0, CAT_CATEGORY_PROGCMD },
963     {"star_point", "star_point", "Option d'affichage", "#display=magenta+star_point", 0, CAT_CATEGORY_PROGCMD },
964     {"stddev(l)", 0, "Ecart-type d'une liste l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
965     {"subst(a,b=c)", 0, "Remplace b par c dans a. Raccourci a(b=c). Pour faire plusieurs remplacements, saisir subst(expr,[b1,b2...],[c1,c2...])", "x^2,x=3", "x+y^2,[x,y],[1,2]", CAT_CATEGORY_ALGEBRA},
966     {"sum(f,k,m,M)", 0, "Somme de l'expression f dependant de k pour k variant de m a M. Exemple sum(k^2,k,1,n)=>*. Raccourci ALPHA F3", "k,k,1,n", "k^2,k", CAT_CATEGORY_CALCULUS},
967     {"svd(A)", 0, "Singular Value Decomposition, renvoie U orthogonale, S vecteur des valeurs singulières, Q orthogonale tels que A=U*diag(S)*tran(Q).", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
968     {"tabvar(f,[x=a..b])", 0, "Tableau de variations de l'expression f, avec arguments optionnels la variable x dans l'intervalle a..b.", "sqrt(x^2+x+1)", "[cos(2t),sin(3t)],t", CAT_CATEGORY_CALCULUS},
969     {"tantque (boucle Xcas)", "tantque  faire  ftantque;", "Boucle indefinie.", "#j:=13; tantque j!=1 faire j:=ifte(even(j),j/2,3j+1); print(j); ftantque;", 0, CAT_CATEGORY_PROG},
970     {"taylor(f,x=a,n,[polynom])", 0, "Developpement de Taylor de l'expression f en x=a a l'ordre n, ajouter le parametre polynom pour enlever le terme de reste.","sin(x),x=0,5", "sin(x),x=0,5,polynom", CAT_CATEGORY_CALCULUS},
971     {"tchebyshev1(n)", 0, "Polynome de Tchebyshev de 1ere espece: cos(n*x)=T_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL},
972     {"tchebyshev2(n)", 0, "Polynome de Tchebyshev de 2eme espece: sin((n+1)*x)=sin(x)*U_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL},
973     {"tcollect(expr)", 0, "Linearisation trigonometrique et regroupement.","sin(x)+cos(x)", 0, CAT_CATEGORY_TRIG},
974     {"texpand(expr)", 0, "Developpe les fonctions trigonometriques, exp et ln.","sin(3x)", "ln(x*y)", CAT_CATEGORY_TRIG},
975     {"time(cmd)", 0, "Temps pour effectuer une commande ou mise a l'heure de horloge","int(1/(x^4+1),x)","8,0", CAT_CATEGORY_PROG},
976     {"tlin(expr)", 0, "Linearisation trigonometrique de l'expression.","sin(x)^3", 0, CAT_CATEGORY_TRIG},
977     {"tourne_droite n", "tourne_droite ", "La tortue tourne de n degres, par defaut n=90", "#tourne_droite 45", 0, CAT_CATEGORY_LOGO},
978     {"tourne_gauche n", "tourne_gauche ", "La tortue tourne de n degres, par defaut n=90", "#tourne_gauche 45", 0, CAT_CATEGORY_LOGO},
979     {"trace(A)", 0, "Trace de la matrice A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
980     {"tran(A)", 0, "Transposee de la matrice A. Pour la transconjuguee utiliser trn(A) ou A^*.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
981     {"triangle_point", "triangle_point", "Option d'affichage", "#display=yellow+triangle_point", 0, CAT_CATEGORY_PROGCMD},
982     {"trig2exp(expr)", 0, "Convertit les fonctions trigonometriques en exponentielles.","cos(x)^3", 0, CAT_CATEGORY_TRIG},
983     {"trigcos(expr)", 0, "Exprime sin^2 et tan^2 avec cos^2.","sin(x)^4", 0, CAT_CATEGORY_TRIG},
984     {"trigsin(expr)", 0, "Exprime cos^2 et tan^2 avec sin^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG},
985     {"trigtan(expr)", 0, "Exprime cos^2 et sin^2 avec tan^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG},
986     {"uniformd(a,b,x)", 0, "loi uniforme sur [a,b] de densite 1/(b-a)", 0, 0, CAT_CATEGORY_PROBA},
987     {"v augmente_de n", " augmente_de ", "La variable v augmente de n, ou de n %", "#v:=3; v augmente_de 1", 0, CAT_CATEGORY_SOFUS},
988     {"v diminue_de n", " diminue_de ", "La variable v diminue de n, ou de n %", "#v:=3; v diminue_de 1", 0, CAT_CATEGORY_SOFUS},
989     {"v est_divise_par n", " est_divise_par ", "La variable v est divisee par n", "#v:=3; v est_divise_par 2", 0, CAT_CATEGORY_SOFUS},
990     {"v est_eleve_puissance n", " est_eleve_puissance ", "La variable v est eleveee a la puissance n", "#v:=3; v est_eleve_puissance 2", 0, CAT_CATEGORY_SOFUS},
991     {"v est_multiplie_par n", " est_multiplie_par ", "La variable v est multipliee par n", "#v:=3; v est_multiplie_par 2", 0, CAT_CATEGORY_SOFUS},
992 				     //{"version", "version()", "Khicas 1.5.0, (c) B. Parisse et al. www-fourier.ujf-grenoble.fr/~parisse. License GPL version 2. Interface adaptee d'Eigenmath pour Casio, G. Maia, http://gbl08ma.com", 0, 0, CAT_CATEGORY_PROGCMD},
993     {"write(\"filename\",var)", "write(\"", "Sauvegarde une ou plusieurs variables dans un fichier. Par exemple f(x):=x^2; write(\"func_f\",f).",  0, 0, CAT_CATEGORY_PROGCMD},
994     {"yellow", "yellow", "Option d'affichage", "#display=yellow", 0, CAT_CATEGORY_PROGCMD},
995     {"|", "|", "Ou logique", "#1|2", 0, CAT_CATEGORY_PROGCMD},
996     {"~", "~", "Complement", "#~7", 0, CAT_CATEGORY_PROGCMD},
997   };
998 
999 const catalogFunc completeCaten[] = { // list of all functions (including some not in any category)
1000   {" loop for", "for ", "Defined loop.", "#\nfor ", 0, CAT_CATEGORY_PROG},
1001   {" loop in list", "for in", "Loop on all elements of a list.", "#\nfor in", 0, CAT_CATEGORY_PROG},
1002   {" loop while", "while ", "Undefined loop.", "#\nwhile ", 0, CAT_CATEGORY_PROG},
1003   {" test if", "if ", "Test", "#\nif ", 0, CAT_CATEGORY_PROG},
1004   {" test else", "else ", "Test false case", 0, 0, CAT_CATEGORY_PROG},
1005   {" function def", "f(x):=", "Definition of function.", "#\nf(x):=", 0, CAT_CATEGORY_PROG},
1006   {" local j,k;", "local ", "Local variables declaration (Xcas)", 0, 0, CAT_CATEGORY_PROG},
1007   {" range(a,b)", 0, "In range [a,b) (a included, b excluded)", "# in range(1,10)", 0, CAT_CATEGORY_PROG},
1008   {" return res", "return ", "Leaves current function and returns res.", 0, 0, CAT_CATEGORY_PROG},
1009   {" edit list ", "list ", "List creation wizzard.", 0, 0, CAT_CATEGORY_LIST},
1010   {" edit matrix ", "matrix ", "Matrix creation wizzard.", 0, 0, CAT_CATEGORY_MATRIX},
1011     {" mksa(x)", 0, "Conversion to MKSA units", 0, 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
1012     {" ufactor(a,b)", 0, "Factorize unit b in a", "100_J,1_kW", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
1013     {" usimplify(a)", 0, "Simplify unit", "100_l/10_cm^2", 0, CAT_CATEGORY_PHYS | (CAT_CATEGORY_UNIT << 8)},
1014   {"!", "!", "Logical not (prefix) or factorial of n (suffix).", "#7!", "~!b", CAT_CATEGORY_PROGCMD},
1015   {"#", "#", "Python comment, for Xcas comment type //. Shortcut ALPHA F2", 0, 0, CAT_CATEGORY_PROG},
1016   {"%", "%", "a % b means a modulo b", 0, 0, CAT_CATEGORY_ARIT | (CAT_CATEGORY_PROGCMD << 8)},
1017   {"&", "&", "Logical and or +", "#1&2", 0, CAT_CATEGORY_PROGCMD},
1018   {":=", ":=", "Set variable value. Shortcut SHIFT F1", "#a:=3", 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)},
1019   {"<", "<", "Shortcut SHIFT F2", 0, 0, CAT_CATEGORY_PROGCMD},
1020   {"=>", "=>", "Store value in variable or conversion (touche ->). For example 5=>a or x^4-1=>* or (x+1)^2=>+ or sin(x)^2=>cos.", "#5=>a", "#15_ft=>_cm", CAT_CATEGORY_PROGCMD | (CAT_CATEGORY_PHYS <<8) | (CAT_CATEGORY_UNIT << 16)},
1021   {">", ">", "Shortcut F2.", 0, 0, CAT_CATEGORY_PROGCMD},
1022   {"\\", "\\", "\\ char", 0, 0, CAT_CATEGORY_PROGCMD},
1023   {"_", "_", "_ char, shortcut (-).", 0, 0, CAT_CATEGORY_PROGCMD},
1024     {"_(km/h)", "_(km/h)", "Speed kilometer per hour", 0, 0, CAT_CATEGORY_UNIT},
1025     {"_(m/s)", "_(m/s)", "Speed meter/second", 0, 0, CAT_CATEGORY_UNIT},
1026     {"_(m/s^2)", "_(m/s^2)", "Acceleration", 0, 0, CAT_CATEGORY_UNIT},
1027     {"_(m^2/s)", "_(m^2/s)", "Viscosity", 0, 0, CAT_CATEGORY_UNIT},
1028     {"_A", 0, "Ampere", 0, 0, CAT_CATEGORY_UNIT},
1029     {"_Bq", 0, "Becquerel", 0, 0, CAT_CATEGORY_UNIT},
1030     {"_C", 0, "Coulomb", 0, 0, CAT_CATEGORY_UNIT},
1031     {"_Ci", 0, "Curie", 0, 0, CAT_CATEGORY_UNIT},
1032     {"_F", 0, "Farad", 0, 0, CAT_CATEGORY_UNIT},
1033     {"_F_", 0, "Faraday constant", 0, 0, CAT_CATEGORY_PHYS},
1034     {"_G_", 0, "Gravitation force=_G_*m1*m2/r^2", 0, 0, CAT_CATEGORY_PHYS},
1035     {"_H", 0, "Henry", 0, 0, CAT_CATEGORY_UNIT},
1036     {"_Hz", 0, "Hertz", 0, 0, CAT_CATEGORY_UNIT},
1037     {"_J", 0, "Joule=kg*m^2/s^2", 0, 0, CAT_CATEGORY_UNIT},
1038     {"_K", 0, "Temperature in Kelvin", 0, 0, CAT_CATEGORY_UNIT},
1039     {"_Kcal", 0, "Energy kilo-calorie", 0, 0, CAT_CATEGORY_UNIT},
1040     {"_MeV", 0, "Energy mega-electron-Volt", 0, 0, CAT_CATEGORY_UNIT},
1041     {"_N", 0, "Force Newton=kg*m/s^2", 0, 0, CAT_CATEGORY_UNIT},
1042     {"_NA_", 0, "Avogadro constant", 0, 0, CAT_CATEGORY_PHYS},
1043     {"_Ohm", 0, "Ohm", 0, 0, CAT_CATEGORY_UNIT},
1044     {"_PSun_", 0, "Sun power", 0, 0, CAT_CATEGORY_PHYS},
1045     {"_Pa", 0, "Pressure in Pascal=kg/m/s^2", 0, 0, CAT_CATEGORY_UNIT},
1046     {"_REarth_", 0, "Earth radius", 0, 0, CAT_CATEGORY_PHYS},
1047     {"_RSun_", 0, "Sun radius", 0, 0, CAT_CATEGORY_PHYS},
1048     {"_R_", 0, "Boltzmann constant (per mol)", 0, 0, CAT_CATEGORY_PHYS},
1049     {"_S", 0, "", 0, 0, CAT_CATEGORY_UNIT},
1050     {"_StdP_", 0, "Standard pressure", 0, 0, CAT_CATEGORY_PHYS},
1051     {"_StdT_", 0, "Standard temperature (0 degre Celsius in Kelvins)", 0, 0, CAT_CATEGORY_PHYS},
1052     {"_Sv", 0, "Sievert", 0, 0, CAT_CATEGORY_UNIT},
1053     {"_T", 0, "Tesla", 0, 0, CAT_CATEGORY_UNIT},
1054     {"_V", 0, "Volt", 0, 0, CAT_CATEGORY_UNIT},
1055     {"_Vm_", 0, "Volume molaire", 0, 0, CAT_CATEGORY_PHYS},
1056     {"_W", 0, "Watt=kg*m^2/s^3", 0, 0, CAT_CATEGORY_UNIT},
1057     {"_Wb", 0, "Weber", 0, 0, CAT_CATEGORY_UNIT},
1058     {"_alpha_", 0, "fine structure constant", 0, 0, CAT_CATEGORY_PHYS},
1059     {"_c_", 0, "speed of light", 0, 0, CAT_CATEGORY_PHYS},
1060     {"_cd", 0, "candela", 0, 0, CAT_CATEGORY_UNIT},
1061   {"_cdf", "_cdf", "Suffix to get a cumulative distribution function. Type F2 for inverse cumulative distribution function _icdf suffix.", "#_icdf", 0, CAT_CATEGORY_PROBA},
1062     {"_d", 0, "day", 0, 0, CAT_CATEGORY_UNIT},
1063     {"_deg", 0, "degree", 0, 0, CAT_CATEGORY_UNIT},
1064     {"_eV", 0, "electron-Volt", 0, 0, CAT_CATEGORY_UNIT},
1065     {"_epsilon0_", 0, "vacuum permittivity", 0, 0, CAT_CATEGORY_PHYS},
1066     {"_ft", 0, "feet", 0, 0, CAT_CATEGORY_UNIT},
1067     {"_g_", 0, "Earth gravity (ground)", 0, 0, CAT_CATEGORY_PHYS},
1068     {"_grad", 0, "grades (angle unit(", 0, 0, CAT_CATEGORY_UNIT},
1069     {"_h", 0, "Hour", 0, 0, CAT_CATEGORY_UNIT},
1070     {"_h_", 0, "Planck constant", 0, 0, CAT_CATEGORY_PHYS},
1071     {"_ha", 0, "hectare", 0, 0, CAT_CATEGORY_UNIT},
1072     {"_hbar_", 0, "Planck constant/(2*pi)", 0, 0, CAT_CATEGORY_PHYS},
1073     {"_inch", 0, "inches", 0, 0, CAT_CATEGORY_UNIT},
1074     {"_kWh", 0, "kWh", 0, 0, CAT_CATEGORY_UNIT},
1075     {"_k_", 0, "Boltzmann constant", 0, 0, CAT_CATEGORY_PHYS},
1076     {"_kg", 0, "kilogram", 0, 0, CAT_CATEGORY_UNIT},
1077     {"_l", 0, "liter", 0, 0, CAT_CATEGORY_UNIT},
1078     {"_m", 0, "meter", 0, 0, CAT_CATEGORY_UNIT},
1079     {"_mEarth_", 0, "Earth mass", 0, 0, CAT_CATEGORY_PHYS},
1080     {"_m^2", 0, "Area in m^2", 0, 0, CAT_CATEGORY_UNIT},
1081     {"_m^3", 0, "Volume in m^3", 0, 0, CAT_CATEGORY_UNIT},
1082     {"_me_", 0, "electron mass", 0, 0, CAT_CATEGORY_PHYS},
1083     {"_miUS", 0, "US miles", 0, 0, CAT_CATEGORY_UNIT},
1084     {"_mn", 0, "minute", 0, 0, CAT_CATEGORY_UNIT},
1085     {"_mp_", 0, "proton mass", 0, 0, CAT_CATEGORY_PHYS},
1086     {"_mpme_", 0, "proton/electron mass-ratio", 0, 0, CAT_CATEGORY_PHYS},
1087     {"_mu0_", 0, "", 0, 0, CAT_CATEGORY_PHYS},
1088     {"_phi_", 0, "magnetic flux quantum", 0, 0, CAT_CATEGORY_PHYS},
1089     {"_plot", "_plot", "Suffix for a regression graph.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1090     {"_qe_", 0, "electron charge", 0, 0, CAT_CATEGORY_PHYS},
1091     {"_qme_", 0, "_q_/_me_", 0, 0, CAT_CATEGORY_PHYS},
1092     {"_rad", 0, "radians", 0, 0, CAT_CATEGORY_UNIT},
1093     {"_rem", 0, "rem", 0, 0, CAT_CATEGORY_UNIT},
1094     {"_s", 0, "second", 0, 0, CAT_CATEGORY_UNIT},
1095     {"_sd_", 0, "Sideral day", 0, 0, CAT_CATEGORY_PHYS},
1096     {"_syr_", 0, "Siderale year", 0, 0, CAT_CATEGORY_PHYS},
1097     {"_tr", 0, "tour (angle unit)", 0, 0, CAT_CATEGORY_UNIT},
1098     {"_yd", 0, "yards", 0, 0, CAT_CATEGORY_UNIT},
1099   {"a and b", " and ", "Logical and", 0, 0, CAT_CATEGORY_PROGCMD},
1100   {"a or b", " or ", "Logical or", 0, 0, CAT_CATEGORY_PROGCMD},
1101   {"abcuv(a,b,c)", 0, "Find 2 polynomial u,v such that a*u+b*v=c","x+1,x^2-2,x", 0, CAT_CATEGORY_POLYNOMIAL},
1102   {"abs(x)", 0, "Absolute value or norm of x x", "-3", "[1,2,3]", CAT_CATEGORY_COMPLEXNUM | (CAT_CATEGORY_REAL<<8)},
1103   {"append", 0, "Adds an element at the end of a list","#l.append(x)", 0, CAT_CATEGORY_LIST},
1104   {"approx(x)", 0, "Approx. value x. Shortcut S-D", "pi", 0, CAT_CATEGORY_REAL},
1105   {"arg(z)", 0, "Angle of complex z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
1106   {"asc(string)", 0, "List of ASCII codes os a string", "\"Hello\"", 0, CAT_CATEGORY_ARIT},
1107   {"assume(hyp)", 0, "Assumption on variable.", "x>1", "x>-1 and x<1", CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)},
1108   {"avance n", "avance ", "Turtle forward n steps, default n=10", "#avance 30", 0, CAT_CATEGORY_LOGO},
1109   {"axes", "axes", "Axes visible or not axes=1 or 0", "#axes=0", 0, CAT_CATEGORY_PROGCMD << 8},
1110   {"baisse_crayon ", "baisse_crayon ", "Turtle moves with the pen writing.", 0, 0, CAT_CATEGORY_LOGO},
1111   {"barplot(list)", 0, "Bar plot of 1-d statistic serie data in list.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1112   {"binomial(n,p,k)", 0, "binomial(n,p,k) probability to get k success with n trials where p is the probability of success of 1 trial. binomial_cdf(n,p,k) is the probability to get at most k successes. binomial_icdf(n,p,t) returns the smallest k such that binomial_cdf(n,p,k)>=t", "10,.5,4", 0, CAT_CATEGORY_PROBA},
1113   {"bitxor", "bitxor", "Exclusive or", "#bitxor(1,2)", 0, CAT_CATEGORY_PROGCMD},
1114   {"black", "black", "Display option", "#display=black", 0, CAT_CATEGORY_PROGCMD},
1115   {"blue", "blue", "Display option", "#display=blue", 0, CAT_CATEGORY_PROGCMD},
1116   {"camembert(list)", 0, "Camembert pie-chart of a 1-d statistical serie.", "[[\"France\",6],[\"Germany\",12],[\"Switzerland\",5]]", 0, CAT_CATEGORY_STATS},
1117   {"cache_tortue ", "cache_tortue ", "Hide turtle (once the picture has been drawn).", 0, 0, CAT_CATEGORY_LOGO},
1118   {"ceiling(x)", 0, "Smallest integer not less than x", "1.2", 0, CAT_CATEGORY_REAL},
1119   {"cfactor(p)", 0, "Factorization over C.", "x^4-1", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)},
1120   {"char(liste)", 0, "Converts a list of ASCII codes to a string.", "[97,98,99]", 0, CAT_CATEGORY_ARIT},
1121   {"charpoly(M,x)", 0, "Characteristic polynomial of matrix M in variable x.", "[[1,2],[3,4]],x", 0, CAT_CATEGORY_MATRIX},
1122   {"circle(center,radius)", 0, "Circle", "2+i,3", "1-i,1+i", CAT_CATEGORY_PROGCMD},
1123   {"clearscreen()", "clearscreen()", "Clear screen.", 0, 0, CAT_CATEGORY_PROGCMD},
1124   {"coeff(p,x,n)", 0, "Coefficient of x^n in polynomial p.", 0, 0, CAT_CATEGORY_POLYNOMIAL},
1125   {"comb(n,k)", 0, "Returns nCk", "10,4", 0, CAT_CATEGORY_PROBA},
1126   {"cond(A,[1,2,inf])", 0, "Nombre de condition d'une matrice par rapport a la norme specifiee (par defaut 1)", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1127   {"conj(z)", 0, "Complex conjugate of z.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
1128   {"correlation(l1,l2)", 0, "Correlation of lists l1 and l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1129   {"covariance(l1,l2)", 0, "Covariance of lists l1 and l2", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1130   {"cpartfrac(p,x)", 0, "Partial fraction decomposition over C.", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA | (CAT_CATEGORY_COMPLEXNUM << 8)},
1131   {"crayon ", "crayon ", "Turtle drawing color", "#crayon red", 0, CAT_CATEGORY_LOGO},
1132   {"cross(u,v)", 0, "Cross product of vectors u and v.","[1,2,3],[0,1,3]", 0, CAT_CATEGORY_LINALG},
1133   {"csolve(equation,x)", 0, "Solve equation (or polynomial system) in exact mode over the complex numbers.","x^2+x+1=0", 0, CAT_CATEGORY_SOLVE| (CAT_CATEGORY_COMPLEXNUM << 8)},
1134   {"curl(u,vars)", 0, "Curl of vector u.", "[2*x*y,x*z,y*z],[x,y,z]", 0, CAT_CATEGORY_LINALG},
1135   {"cyan", "cyan", "Display option", "#display=cyan", 0, CAT_CATEGORY_PROGCMD},
1136   {"debug(f(args))", 0, "Runs user function f in step by step mode.", 0, 0, CAT_CATEGORY_PROG},
1137   {"degree(p,x)", 0, "Degre of polynomial p in x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL},
1138   {"denom(x)", 0, "Denominator of expression x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL},
1139   {"desolve(equation,t,y)", 0, "Exact differential equation solving.", "desolve([y'+y=exp(x),y(0)=1])", "[y'=[[1,2],[2,1]]*y+[x,x+1],y(0)=[1,2]]", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_CALCULUS << 8)},
1140   {"det(A)", 0, "Determinant of matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1141   {"diff(f,var,[n])", 0, "Derivative of expression f with respect to var (order n, n=1 by default), for example diff(sin(x),x) or diff(x^3,x,2). For derivation with respect to x, run f' (shortcut F3). For the gradient of f, var is the list of variables.", "sin(x),x", "sin(x^2),x,3", CAT_CATEGORY_CALCULUS},
1142   {"display", "display", "Display option", "#display=red", 0, CAT_CATEGORY_PROGCMD},
1143   {"disque n", "disque ", "Filled circle tangent to the turtle, radius n. Run disque n,theta for a filled arc of circle, theta in degrees, or disque n,theta,segment for a segment of circle.", "#disque 30", "#disque(30,90)", CAT_CATEGORY_LOGO},
1144   {"dot(a,b)", 0, "Dot product of 2 vectors. Shortcut: *", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_LINALG},
1145   {"draw_arc(x1,y1,rx,ry,theta1,theta2,c)", 0, "Pixelised arc of ellipse.", "100,100,60,80,0,pi,magenta", 0, CAT_CATEGORY_PROGCMD},
1146   {"draw_circle(x1,y1,r,c)", 0, "Pixelised circle. Option: filled", "100,100,60,cyan+filled", 0, CAT_CATEGORY_PROGCMD},
1147   {"draw_line(x1,y1,x2,y2,c)", 0, "Pixelised line.", "100,50,300,200,blue", 0, CAT_CATEGORY_PROGCMD},
1148   {"draw_pixel(x,y,color)", 0, "Colors pixel x,y. Run draw_pixel() to synchronise screen.", 0, 0, CAT_CATEGORY_PROGCMD},
1149   {"draw_polygon([[x1,y1],...],c)", 0, "Pixelised polygon.", "[[100,50],[30,20],[60,70]],red+filled", 0, CAT_CATEGORY_PROGCMD},
1150   {"draw_rectangle(x,y,w,h,c)", 0, "Rectangle.", "100,50,30,20,red+filled", 0, CAT_CATEGORY_PROGCMD},
1151   {"draw_string(s,x,y,c)", 0, "Draw string s at pixel x,y", "\"Bonjour\",80,60", 0, CAT_CATEGORY_PROGCMD},
1152 #ifndef TURTLETAB
1153   {"ecris ", "ecris ", "Write at turtle position", "#ecris \"hello\"", 0, CAT_CATEGORY_LOGO},
1154 #endif
1155   {"efface", "efface", "Reset turtle", 0, 0, CAT_CATEGORY_LOGO},
1156   {"egcd(A,B)", 0, "Find polynomials U,V,D such that A*U+B*V=D=gcd(A,B)","x^2+3x+1,x^2-5x-1", 0, CAT_CATEGORY_POLYNOMIAL},
1157   {"elif test", "elif ", "Test cascade", 0, 0, CAT_CATEGORY_PROG},
1158   {"eigenvals(A)", 0, "Eigenvalues of matrix  A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1159   {"eigenvects(A)", 0, "Eigenvectors of matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1160   {"erf(x)", 0, "Error function of x.", "1.2", 0, CAT_CATEGORY_PROBA},
1161   {"erfc(x)", 0, "Complementary error function of x.", "1.2", 0, CAT_CATEGORY_PROBA},
1162   {"euler(n)",0,"Euler indicatrix: number of integers < n coprime with n","25",0,CAT_CATEGORY_ARIT},
1163   {"eval(f)", 0, "Evals f.", 0, 0, CAT_CATEGORY_PROGCMD},
1164   {"evalc(z)", 0, "Write z=x+i*y.", "1/(1+i*sqrt(3))", 0, CAT_CATEGORY_COMPLEXNUM},
1165   {"exact(x)", 0, "Converts x to a rational. Shortcut shift S-D", "1.2", 0, CAT_CATEGORY_REAL},
1166   {"exp2trig(expr)", 0, "Convert complex exponentials to sin/cos", "exp(i*x)", 0, CAT_CATEGORY_TRIG},
1167   {"exponential_regression(Xlist,Ylist)", 0, "Exponential regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1168   {"exponential_regression_plot(Xlist,Ylist)", 0, "Exponential regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];exponential_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1169   {"exponentiald(lambda,x)", 0, "Exponential distribution law of  parameter lambda. exponentiald_cdf(lambda,x) probability that \"exponential distribution <=x\" e.g. exponentiald_cdf(2,3). exponentiald_icdf(lambda,t) returns x such that \"exponential distribution <=x\" has probability t, e.g, exponentiald_icdf(2,0.95) ", "5.1,3.4", 0, CAT_CATEGORY_PROBA},
1170   {"extend", 0, "Merge 2 lists. Note that + does not merge lists, it adds vectors","#l1.extend(l2)", 0, CAT_CATEGORY_LIST},
1171   {"factor(p,[x])", 0, "Factors polynomial p (run ifactor for an integer). Shortcut: p=>*", "x^4-1", "x^6+1,sqrt(3)", CAT_CATEGORY_ALGEBRA| (CAT_CATEGORY_POLYNOMIAL << 8)},
1172   {"filled", "filled", "Display option", 0, 0, CAT_CATEGORY_PROGCMD},
1173   {"float(x)", 0, "Converts x to a floating point value.", "pi", 0, CAT_CATEGORY_REAL},
1174   {"floor(x)", 0, "Largest integer not greater than x", "pi", 0, CAT_CATEGORY_REAL},
1175   {"fourier_an(f,x,T,n,a)", 0, "Cosine Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS},
1176   {"fourier_bn(f,x,T,n,a)", 0, "Sine Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS},
1177   {"fourier_cn(f,x,T,n,a)", 0, "Exponential Fourier coefficients of f", "x^2,x,2*pi,n,-pi", 0, CAT_CATEGORY_CALCULUS},
1178   {"from math/... import *", "from math import *", "Access to math or to random functions ([random]) or turtle with English commandnames [turtle]. Math import is not required in KhiCAS", "#from random import *", "#from turtle import *", CAT_CATEGORY_PROG},
1179   {"fsolve(equation,x=a..b)", 0, "Approx equation solving in interval a..b.","cos(x)=x,x=0..1", "cos(x)-x,x=0.0", CAT_CATEGORY_SOLVE},
1180   // {"function f(x):...", "function f(x) local y;   ffunction:;", "Function definition.", "#function f(x) local y; y:=x^2; return y; ffunction:;", 0, CAT_CATEGORY_PROG},
1181   {"gauss(q)", 0, "Quadratic form reduction", "x^2+x*y+x*z+y^2+z^2,[x,y,z]", 0, CAT_CATEGORY_LINALG},
1182   {"gcd(a,b,...)", 0, "Greatest common divisor. See also iegcd and egcd for extended GCD.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)},
1183   {"gl_x", "gl_x", "Display settings X gl_x=xmin..xmax", "#gl_x=0..2", 0, CAT_CATEGORY_PROGCMD},
1184   {"gl_y", "gl_y", "Display settings Y gl_y=ymin..ymax", "#gl_y=-1..1", 0, CAT_CATEGORY_PROGCMD},
1185   {"gramschmidt(M)", 0, "Gram-Schmidt orthonormalization (line vectors or linearly independant set of vectors)", "[[1,2,3],[4,5,6]]", "[1,1+x],(p,q)->integrate(p*q,x,-1,1)", CAT_CATEGORY_LINALG},
1186   {"green", "green", "Display option", "#display=green", 0, CAT_CATEGORY_PROGCMD},
1187   {"halftan(expr)", 0, "Convert cos, sin, tan with tan(angle/2).","cos(x)", 0, CAT_CATEGORY_TRIG},
1188   {"hermite(n)", 0, "n-th Hermite polynomial", "10", 0, CAT_CATEGORY_POLYNOMIAL},
1189   {"hilbert(n)", 0, "Hilbert matrix of order n.", "4", 0, CAT_CATEGORY_MATRIX},
1190   {"histogram(list,min,size)", 0, "Histogram of data in list, classes begin at min of size size.","ranv(100,uniformd,0,1),0,0.1", 0, CAT_CATEGORY_STATS},
1191   {"iabcuv(a,b,c)", 0, "Find 2 integers u,v such that a*u+b*v=c","23,13,15", 0, CAT_CATEGORY_ARIT},
1192   {"ichinrem([a,m],[b,n])", 0,"Integer chinese remainder of a mod m and b mod n.", "[3,13],[2,7]", 0, CAT_CATEGORY_ARIT},
1193   {"idivis(n)", 0, "Returns the list of divisors of an integer n.", "10", 0, CAT_CATEGORY_ARIT},
1194   {"idn(n)", 0, "Identity matrix of order n", "4", 0, CAT_CATEGORY_MATRIX},
1195   {"iegcd(a,b)", 0, "Find integers u,v,d such that a*u+b*v=d=gcd(a,b)","23,13", 0, CAT_CATEGORY_ARIT},
1196   {"ifactor(n)", 0, "Factorization of an integer (not too large!). Shortcut n=>*", 0, 0, CAT_CATEGORY_ARIT},
1197   {"ilaplace(f,s,x)", 0, "Inverse Laplace transform of f", "s/(s^2+1),s,x", 0, CAT_CATEGORY_CALCULUS},
1198   {"im(z)", 0, "Imaginary part.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
1199   {"inf", "inf", "Plus infinity. -inf for minus infinity and infinity for unsigned/complex infinity. Shortcut shift INS.", "oo", 0, CAT_CATEGORY_CALCULUS},
1200   {"input()", "input()", "Read a string from keyboard", 0, 0, CAT_CATEGORY_PROG},
1201   {"integrate(f,x,[a,b])", 0, "Antiderivative of f with respect to x, like integrate(x*sin(x),x). For definite integral enter optional arguments a and b, like integrate(x*sin(x),x,0,pi). Shortcut SHIFT F3.", "x*sin(x),x", "cos(x)/(1+x^4),x,0,inf", CAT_CATEGORY_CALCULUS},
1202   {"interp(X,Y)", 0, "Lagrange interpolation at points (xi,yi) where X is the list of xi and Y of yi. If interp is passed as 3rd argument, returns the divided differences list.", "[1,2,3,4,5],[0,1,3,4,4]", "[1,2,3,4,5],[0,1,3,4,4],interp", CAT_CATEGORY_POLYNOMIAL},
1203   {"inv(A)", 0, "Inverse of A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1204   {"iquo(a,b)", 0, "Integer quotient of a and b.", "23,13", 0, CAT_CATEGORY_ARIT},
1205   {"irem(a,b)", 0,"Integer remainder of a and b.", "23,13", 0, CAT_CATEGORY_ARIT},
1206   {"isprime(n)", 0, "Returns 1 if n is prime, 0 otherwise.", "11", "10", CAT_CATEGORY_ARIT},
1207   {"jordan(A)", 0, "Jordan normal form of matrix A, returns P and D such that P^-1*A*P=D", "[[1,2],[3,4]]", "[[1,1,-1,2,-1],[2,0,1,-4,-1],[0,1,1,1,1],[0,1,2,0,1],[0,0,-3,3,-1]]", CAT_CATEGORY_MATRIX},
1208   {"laguerre(n,a,x)", 0, "n-ieme Laguerre polynomial (default a=0).", "10", 0, CAT_CATEGORY_POLYNOMIAL},
1209   {"laplace(f,x,s)", 0, "Laplace transform of f","sin(x),x,s", 0, CAT_CATEGORY_CALCULUS},
1210   {"lcm(a,b,...)", 0, "Least common multiple.", "23,13", "x^2-1,x^3-1", CAT_CATEGORY_ARIT | (CAT_CATEGORY_POLYNOMIAL << 8)},
1211   {"lcoeff(p,x)", 0, "Leading coefficient of polynomial p in x.", "x^4-1", 0, CAT_CATEGORY_POLYNOMIAL},
1212   {"legendre(n)", 0, "n-the Legendre polynomial.", "10", "10,t", CAT_CATEGORY_POLYNOMIAL},
1213 #ifdef RELEASE
1214   {"len(l)", 0, "Size of a list.", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_LIST},
1215 #endif
1216   {"leve_crayon ", "leve_crayon ", "Turtle moves without trace.", 0, 0, CAT_CATEGORY_LOGO},
1217   {"limit(f,x=a)", 0, "Limit of f at x = a. Add 1 or -1 for unidirectional limits, e.g. limit(sin(x)/x,x=0) or limit(abs(x)/x,x=0,1). Shortcut: SHIFT MIXEDFRAC", "sin(x)/x,x=0", "exp(-1/x),x=0,1", CAT_CATEGORY_CALCULUS},
1218   {"line(equation)", 0, "Line of equation", "y=2x+1", 0, CAT_CATEGORY_PROGCMD},
1219   {"line_width_", "line_width_", "Width prefix (2 to 8)", 0, 0, CAT_CATEGORY_PROGCMD},
1220   {"linear_regression(Xlist,Ylist)", 0, "Linear regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1221   {"linear_regression_plot(Xlist,Ylist)", 0, "Linear regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];linear_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1222   {"linetan(expr,x,x0)", 0, "Tangent to the graph at x=x0.", "sin(x),x,pi/2", 0, CAT_CATEGORY_PLOT},
1223   {"linsolve([eq1,eq2,..],[x,y,..])", 0, "Linear system solving. May use the output of lu for O(n^2) solving (see example 2).","[x+y=1,x-y=2],[x,y]", "#p,l,u:=lu([[1,2],[3,4]]); linsolve(p,l,u,[5,6])", CAT_CATEGORY_SOLVE | (CAT_CATEGORY_LINALG <<8) | (CAT_CATEGORY_MATRIX << 16)},
1224   {"logarithmic_regression(Xlist,Ylist)", 0, "Logarithmic egression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1225   {"logarithmic_regression_plot(Xlist,Ylist)", 0, "Logarithmic regression plot.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];logarithmic_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1226   {"lu(A)", 0, "LU decomposition LU of matrix A, P*A=L*U", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1227   {"magenta", "magenta", "Display option", "#display=magenta", 0, CAT_CATEGORY_PROGCMD},
1228   {"map(l,f)", 0, "Maps f on element of list l.","[1,2,3],x->x^2", 0, CAT_CATEGORY_LIST},
1229   {"matpow(A,n)", 0, "Returns matrix A^n", "[[1,2],[3,4]],n","#assume(n>=1);matpow([[0,2],[0,4]],n)",  CAT_CATEGORY_MATRIX},
1230   {"matrix(r,c,func)", 0, "Matrix from a defining function.", "2,3,(j,k)->j^k", 0, CAT_CATEGORY_MATRIX},
1231   {"mean(l)", 0, "Arithmetic mean of list l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1232   {"median(l)", 0, "Median", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1233   {"montre_tortue ", "montre_tortue ", "Displays the turtle", 0, 0, CAT_CATEGORY_LOGO},
1234   {"mult_c_conjugate", 0, "Multiplier par le conjugue complexe.", "1+2*i", 0,  (CAT_CATEGORY_COMPLEXNUM << 8)},
1235   {"mult_conjugate", 0, "Multiplier par le conjugue (sqrt).", "sqrt(2)-sqrt(3)", 0, CAT_CATEGORY_ALGEBRA},
1236   {"normald([mu,sigma],x)", 0, "Normal distribution probability density, by default mu=0 and sigma=1. normald_cdf([mu,sigma],x) probability that \"normal distribution <=x\" e.g. normald_cdf(1.96). normald_icdf([mu,sigma],t) returns x such that \"normal distribution <=x\" has probability t, e.g. normald_icdf(0.975) ", "1.2", 0, CAT_CATEGORY_PROBA},
1237   {"not(x)", 0, "Logical not.", 0, 0, CAT_CATEGORY_PROGCMD},
1238   {"numer(x)", 0, "Numerator of x.", "3/4", 0, CAT_CATEGORY_POLYNOMIAL},
1239   {"odesolve(f(t,y),[t,y],[t0,y0],t1)", 0, "Approx. solution of differential equation y'=f(t,y) and y(t0)=y0, value for t=t1 (add curve to get intermediate values of y)", "sin(t*y),[t,y],[0,1],2", "0..pi,(t,v)->{[-v[1],v[0]]},[0,1]", CAT_CATEGORY_SOLVE},
1240   {"partfrac(p,x)", 0, "Partial fraction expansion. Shortcut p=>+", "1/(x^4-1)", 0, CAT_CATEGORY_ALGEBRA},
1241   {"pas_de_cote n", "pas_de_cote ", "Turtle side jump from n steps, by default n=10", "#pas_de_cote 30", 0, CAT_CATEGORY_LOGO},
1242   {"plot(expr,x)", 0, "Plot an expression. For example plot(sin(x)), plot(ln(x),x.0,5)", "ln(x),x,0,5", "1/x,x=1..5,xstep=1", CAT_CATEGORY_PLOT},
1243 #ifdef RELEASE
1244   {"plotarea(expr,x=a..b,[n,meth])", 0, "Area under curve with specified quadrature.", "1/x,x=1..3,2,trapezoid", 0, CAT_CATEGORY_PLOT},
1245 #endif
1246   {"plotcontour(expr,[x=xm..xM,y=ym..yM],levels)", 0, "Levels of expr.", "x^2+2y^2,[x=-2..2,y=-2..2],[1,2]", 0, CAT_CATEGORY_PLOT},
1247   {"plotfield(f(t,y),[t=tmin..tmax,y=ymin..ymax])", 0, "Plot field of differential equation y'=f(t,y), an optionnally one solution by adding plotode=[t0,y0]", "sin(t*y),[t=-3..3,y=-3..3],plotode=[0,1]", 0, CAT_CATEGORY_PLOT},
1248   {"plotlist(list)", 0, "Plot a list", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_PLOT},
1249   {"plotode(f(t,y),[t=tmin..tmax,y],[t0,y0])", 0, "Plot solution of differential equation y'=f(t,y), y(t0)=y0.", "sin(t*y),[t=-3..3,y],[0,1]", 0, CAT_CATEGORY_PLOT},
1250   {"plotparam([x,y],t)", 0, "Parametric plot. For example plotparam([sin(3t),cos(2t)],t,0,pi) or plotparam(exp(i*t),t,0,pi)", "[sin(3t),cos(2t)],t,0,pi", "[t^2,t^3],t=-1..1,tstep=0.1", CAT_CATEGORY_PLOT},
1251   {"plotpolar(r,theta)", 0, "Polar plot.","cos(3*x),x,0,pi", "1/(1+cos(x)),x=0..pi,xstep=0.05", CAT_CATEGORY_PLOT},
1252   {"plotseq(f(x),x=[u0,m,M],n)", 0, "Plot f(x) on [m,M] and n terms of the sequence defined by u_{n+1}=f(u_n) and u0.","sqrt(2+x),x=[6,0,7],5", 0, CAT_CATEGORY_PLOT},
1253   {"plus_point", "plus_point", "Display option", "#display=blue+plus_point", 0, CAT_CATEGORY_PROGCMD},
1254   {"point(x,y)", 0, "Point", "1,2", 0, CAT_CATEGORY_PLOT},
1255   {"polygon(list)", 0, "Closed polygon.", "1-i,2+i,3", 0, CAT_CATEGORY_PROGCMD},
1256   {"polygonscatterplot(Xlist,Ylist)", 0, "Plot points and polygonal line.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1257   {"polynomial_regression(Xlist,Ylist,n)", 0, "Polynomial regression, degree <= n.", "[1,2,3,4,5],[0,1,3,4,4],2", 0, CAT_CATEGORY_STATS},
1258   {"polynomial_regression_plot(Xlist,Ylist,n)", 0, "Polynomial regression plot, degree <= n.", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];polynomial_regression_plot(X,Y,2);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1259   //{"pour", "pour j de 1 jusque  faire  fpour;", "For loop.","#pour j de 1 jusque 10 faire print(j,j^2); fpour;", 0, CAT_CATEGORY_PROG},
1260   {"power_regression(Xlist,Ylist,n)", 0, "Power regression.", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1261   {"power_regression_plot(Xlist,Ylist,n)", 0, "Power regression graph", "#X,Y:=[1,2,3,4,5],[0,1,3,4,4];power_regression_plot(X,Y);scatterplot(X,Y)", 0, CAT_CATEGORY_STATS},
1262   {"powmod(a,n,p)", 0, "Returns a^n mod p.","123,456,789", 0, CAT_CATEGORY_ARIT},
1263   {"print(expr)", 0, "Print expr in console", 0, 0, CAT_CATEGORY_PROG},
1264   {"proot(p)", 0, "Returns real and complex roots, of polynomial p. Exemple proot([1,2.1,3,4.2]) or proot(x^3+2.1*x^2+3x+4.2)", "x^3+2.1*x^2+3x+4.2", 0, CAT_CATEGORY_POLYNOMIAL},
1265   {"purge(x)", 0, "Clear assigned variable x. Shortcut SHIFT-FORMAT", 0, 0, CAT_CATEGORY_PROGCMD|(CAT_CATEGORY_SOFUS<<8)},
1266   {"python(f)", 0, "Displays f in Python syntax.", 0, 0, CAT_CATEGORY_PROGCMD},
1267   {"python_compat(0|1|2)", 0, "python_compat(0) Xcas syntax, python_compat(1) Python syntax with ^ interpreted as power, python_compat(2) ^ as bit xor", "0", "1", CAT_CATEGORY_PROG},
1268   {"qr(A)", 0, "A=Q*R factorization with Q orthogonal and R upper triangular", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1269   {"quartile1(l)", 0, "1st quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1270   {"quartile3(l)", 0, "3rd quartile", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1271   {"quo(p,q,x)", 0, "Quotient of synthetic division of polynomials p and q (variable x).", 0, 0, CAT_CATEGORY_POLYNOMIAL},
1272   {"quote(x)", 0, "Returns expression x unevaluated.", 0, 0, CAT_CATEGORY_ALGEBRA},
1273   {"rand()", "rand()", "Random real between 0 and 1", 0, 0, CAT_CATEGORY_PROBA},
1274   {"randint(n)", 0, "Random integer between 1 and n", "6", 0, CAT_CATEGORY_PROBA},
1275   {"ranm(n,m,[loi,parametres])", 0, "Random matrix with integer coefficients or according to a probability law (ranv for a vector). Examples ranm(2,3), ranm(3,2,binomial,20,.3), ranm(4,2,normald,0,1)", "4,2,normald,0,1", "3,3,10", CAT_CATEGORY_MATRIX},
1276   {"ranv(n,[loi,parametres])", 0, "Random vector.", "4,normald,0,1", "10,30", CAT_CATEGORY_LINALG},
1277   {"ratnormal(x)", 0, "Puts everything over a common denominator.", 0, 0, CAT_CATEGORY_ALGEBRA},
1278   {"re(z)", 0, "Real part.", "1+i", 0, CAT_CATEGORY_COMPLEXNUM},
1279   {"read(\"filename\")", "read(\"", "Read a file.", 0, 0, CAT_CATEGORY_PROGCMD},
1280   {"rectangle_plein a,b", "rectangle_plein ", "Direct filled rectangle from turtle position, if b is omitted b==a", "#rectangle_plein 30","#rectangle_plein 20,40", CAT_CATEGORY_LOGO},
1281   {"recule n", "recule ", "Turtle backward n steps, n=10 by default", "#recule 30", 0, CAT_CATEGORY_LOGO},
1282   {"red", "red", "Display option", "#display=red", 0, CAT_CATEGORY_PROGCMD},
1283   {"rem(p,q,x)", 0, "Remainder of synthetic division of polynomials p and q (variable x)", 0, 0, CAT_CATEGORY_POLYNOMIAL},
1284 #ifdef RELEASE
1285   {"residue(f(z),z,z0)", 0, "Residue of an expression at z0.", "1/(x^2+1),x,i", 0, CAT_CATEGORY_COMPLEXNUM},
1286 #endif
1287   {"resultant(p,q,x)", 0, "Resultant in x of polynomials p and q.", "#P:=x^3+p*x+q;resultant(P,P',x);", 0, CAT_CATEGORY_POLYNOMIAL},
1288   {"revert(p[,x])", 0, "Revert Taylor series","x+x^2+x^4", 0, CAT_CATEGORY_CALCULUS},
1289   {"rgb(r,g,b)", 0, "color defined from red, green, blue from 0 to 255", "255,0,255", 0, CAT_CATEGORY_PROGCMD},
1290   {"rhombus_point", "rhombus_point", "Display option", "#display=magenta+rhombus_point", 0, CAT_CATEGORY_PROGCMD},
1291   {"rond n", "rond ", "Circle tangent to the turtle, radius n. Run rond n,theta for an arc of circle of theta degrees", 0, 0, CAT_CATEGORY_LOGO},
1292   {"rsolve(equation,u(n),[init])", 0, "Solve a recurrence relation.","u(n+1)=2*u(n)+3,u(n),u(0)=1", "([u(n+1)=3*v(n)+u(n),v(n+1)=v(n)+u(n)],[u(n),v(n)],[u(0)=1,v(0)=2]", CAT_CATEGORY_SOLVE},
1293   {"saute n", "saute ", "Turtle jumps n steps, by default n=10", "#saute 30", 0, CAT_CATEGORY_LOGO},
1294   {"scatterplot(Xlist,Ylist)", 0, "Draws points", "[1,2,3,4,5],[0,1,3,4,4]", 0, CAT_CATEGORY_STATS},
1295   {"segment(A,B)", 0, "Segment", "1,2+i", 0, CAT_CATEGORY_PROGCMD},
1296   {"seq(expr,var,a,b)", 0, "Generates a list from an expression.","j^2,j,1,10", 0, CAT_CATEGORY_PROGCMD},
1297   //{"si", "si  alors  sinon  fsi;", "Test.", "#f(x):=si x>0 alors x; sinon -x; fsi;// valeur absolue", 0, CAT_CATEGORY_PROG},
1298   {"sign(x)", 0, "Returns -1 if x is negative, 0 if x is zero and 1 if x is positive.", 0, 0, CAT_CATEGORY_REAL},
1299   {"simplify(expr)", 0, "Returns x in a simpler form. Shortcut expr=>/", "sin(3x)/sin(x)", 0, CAT_CATEGORY_ALGEBRA},
1300   {"solve(equation,x)", 0, "Exact solving of equation w.r.t. x (or of a polynomial system). Run csolve for complex solutions, linsolve for a linear system. Shortcut SHIFT XthetaT", "x^2-x-1=0,x", "[x^2-y^2=0,x^2-z^2=0],[x,y,z]", CAT_CATEGORY_SOLVE},
1301   {"sort(l)", 0, "Sorts a list.","[3/2,2,1,1/2,3,2,3/2]", "[[1,2],[2,3],[4,3]],(x,y)->when(x[1]==y[1],x[0]>y[0],x[1]>y[1]", CAT_CATEGORY_LIST},
1302   {"square_point", "square_point", "Display option", "#display=cyan+square_point", 0, CAT_CATEGORY_PROGCMD},
1303   {"star_point", "star_point", "Display option", "#display=magenta+star_point", 0, CAT_CATEGORY_PROGCMD},
1304   {"stddev(l)", 0, "Standard deviation of list l", "[3/2,2,1,1/2,3,2,3/2]", 0, CAT_CATEGORY_STATS},
1305   {"subst(a,b=c)", 0, "Substitutes b for c in a. Shortcut a(b=c).", "x^2,x=3", 0, CAT_CATEGORY_ALGEBRA},
1306   {"sum(f,k,m,M)", 0, "Summation of expression f for k from m to M. Exemple sum(k^2,k,1,n)=>*. Shortcut ALPHA F3", "k,k,1,n", 0, CAT_CATEGORY_CALCULUS},
1307   {"svd(A)", 0, "Singular Value Decomposition, returns U orthogonal, S vector of singular values, Q orthogonal such that A=U*diag(S)*tran(Q).", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1308   {"tabvar(f,[x=a..b])", 0, "Table of variations of expression f, optional arguments variable x in interval a..b", "sqrt(x^2+x+1)",  "[cos(t),sin(3t)],t", CAT_CATEGORY_CALCULUS},
1309   //{"tantque", "tantque  faire   ftantque;", "While loop.", "#j:=13; tantque j!=1 faire j:=when(even(j),j/2,3j+1); print(j); ftantque;", 0, CAT_CATEGORY_PROG},
1310   {"taylor(f,x=a,n,[polynom])", 0, "Taylor expansion of f of x at a order n, add parameter polynom to remove remainder term.","sin(x),x=0,5", "sin(x),x=0,5,polynom", CAT_CATEGORY_CALCULUS},
1311   {"tchebyshev1(n)", 0, "Tchebyshev polynomial 1st kind: cos(n*x)=T_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL},
1312   {"tchebyshev2(n)", 0, "Tchebyshev polynomial 2nd kind: sin((n+1)*x)=sin(x)*U_n(cos(x))", "10", 0, CAT_CATEGORY_POLYNOMIAL},
1313   {"tcollect(expr)", 0, "Linearize and collect trig functions.","sin(x)+cos(x)", 0, CAT_CATEGORY_TRIG},
1314   {"texpand(expr)", 0, "Expand trigonometric, exp and ln functions.","sin(3x)", 0, CAT_CATEGORY_TRIG},
1315   {"time(cmd)", 0, "Time to run a command or set the clock","int(1/(x^4+1),x)","8,0", CAT_CATEGORY_PROG},
1316   {"tlin(expr)", 0, "Trigonometric linearization of expr.","sin(x)^3", 0, CAT_CATEGORY_TRIG},
1317   {"tourne_droite n", "tourne_droite ", "Turtle turns right n degrees, n=90 by default", 0, 0, CAT_CATEGORY_LOGO},
1318   {"tourne_gauche n", "tourne_gauche ", "Turtle turns left n degrees, n=90 by default", 0, 0, CAT_CATEGORY_LOGO},
1319   {"trace(A)", 0, "Trace of the matrix A.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1320   {"tran(A)", 0, "Transposes matrix A. Transconjugate command is trn(A) or A^*.", "[[1,2],[3,4]]", 0, CAT_CATEGORY_MATRIX},
1321   {"triangle_point", "triangle_point", "Display option", "#display=yellow+triangle_point", 0, CAT_CATEGORY_PROGCMD},
1322   {"trig2exp(expr)", 0, "Convert complex exponentials to trigonometric functions","cos(x)^3", 0, CAT_CATEGORY_TRIG},
1323   {"trigcos(expr)", 0, "Convert sin^2 and tan^2 to cos^2.","sin(x)^4", 0, CAT_CATEGORY_TRIG},
1324   {"trigsin(expr)", 0, "Convert cos^2 and tan^2 to sin^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG},
1325   {"trigtan(expr)", 0, "Convert cos^2 and sin^2 to tan^2.","cos(x)^4", 0, CAT_CATEGORY_TRIG},
1326   {"uniformd(a,b,x)", "uniformd", "uniform law on [a,b] of density 1/(b-a)", 0, 0, CAT_CATEGORY_PROBA},
1327   //{"version", "version()", "Khicas 1.5.0, (c) B. Parisse et al. www-fourier.ujf-grenoble.fr/~parisse\nLicense GPL version 2. Interface adapted from Eigenmath for Casio, G. Maia, http://gbl08ma.com. Do not use if CAS calculators are forbidden.", 0, 0, CAT_CATEGORY_PROGCMD},
1328   {"write(\"filename\",var)", "write(\"", "Save 1 or more variables in a file. For example f(x):=x^2; write(\"func_f\",f).",  0, 0, CAT_CATEGORY_PROGCMD},
1329   {"yellow", "yellow", "Display option", "#display=yellow", 0, CAT_CATEGORY_PROGCMD},
1330   {"|", "|", "Logical or", "#1|2", 0, CAT_CATEGORY_PROGCMD},
1331   {"~", "~", "Complement", "#~7", 0, CAT_CATEGORY_PROGCMD},
1332 };
1333 
1334   const char aide_khicas_string[]="Aide Khicas";
1335 #ifdef NUMWORKS
1336   const char shortcuts_fr_string[]="Raccourcis clavier (shell et editeur)\nshift-/: %\nalpha shift \": '\nshift--: \\\nshift-*: factor\nshift-+: normal\nshift-1 a 6: selon bandeau en bas\nshift-7: matrices\nshift-8: listes\nshift-9:arithmetique\nshift-0: polynomes\nshift-.: reels\nshift-10^: programme\nvar: liste des variables (shell) ou dessin tortue (editeur)\n\nshift-x^y (sto) renvoie =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: Editeur 2d ou graphique ou texte selon objet\nshift-6: editeur texte\n+ ou - modifie un parametre en surbrillance\n\nEditeur d'expressions\nshift-cut: defaire/refaire (1 fois)\npave directionnel: deplace la selection dans l'arborescence de l'expression\nshift-droit/gauche echange selection avec argument a droite ou a gauche\nalpha-droit/gauche dans une somme ou un produit: augmente la selection avec argument droit ou gauche\nshift-4: Editer selection, shift-5: taille police + ou - grande\nEXE: evaluer la selection\nshift-6: valeur approchee\nBackspace: supprime l'operateur racine de la selection\n\nEditeur de scripts\nEXE: passage a la ligne\nshift-CUT: defaire/refaire (1 fois)\nshift-COPY: marque le debut de la selection, deplacer le curseur vers la fin puis Backspace pour effacer ou shift-COPY pour copier sans effacer. shift-PASTE pour coller.\nHome-6 recherche seule: entrer un mot puis EXE puis EXE. Taper EXE pour l'occurence suivante, Back pour annuler.\nHome-6 remplacer: entrer un mot puis EXE puis le remplacement et EXE. Taper EXE ou Back pour remplacer ou non et passer a l'occurence suivante, AC pour annuler\nOK: tester syntaxe\n\nRaccourcis Graphes:\n+ - zoom\n(-): zoomout selon y\n*: autoscale\n/: orthonormalisation\nOPTN: axes on/off";
1337   const char shortcuts_en_string[]="Keyboard shortcuts (shell and editor)\nshift-/: %\nalpha shift \": '\nshift--: \\\nshift-*: factor\nshift-+: normal\nshift-1 to 6: cf. screen bottom\nshift-7: matrices\nshift-8: lists\nshift-9:arithmetic\nshift-0: polynomials\nshift-.: reals\nshift-10^: programs\nvar: variables list (shell) or turtle screen (editor)\n\nshift-x^y (sto) returns =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: 2d editor or graph or text\nshift-6: text edit\n+ ou - modifies selected slider\n\nExpressions editor\nshift-cut: undo/redo (1 fois)\nkeypad: move selection inside expression tree\nshift-right/left exchange selection with right or left argument\nalpha-right/left: inside a sum or product: increase selection with right or left argument\nshift-4: Edit selection, shift-5: change fontsize\nEXE: eval selection\nshift-6: approx value\nBackspace: suppress selection's rootnode operator\n\nScript Editor\nEXE: newline\nshift-CUT: undo/redo (1 time)\nshift-COPY: marks selection begin, move the cursor to the end, then hit Backspace to erase or shift-COPY to copy (no erase). shift-PASTE to paste.\nHome-6 search: enter a word then EXE then again EXE. Type EXE for next occurence, Back to cancel.\nHome-6 replace: enter a word then EXE then replacement word then EXE. Type EXE or Back to replace or ignore and go to next occurence, AC to cancel\nOK: test syntax\n\nGraph shortcuts:\n+ - zoom\n(-): zoomout along y\n*: autoscale\n/: orthonormalization\nOPTN: axes on/off";
1338 #else
1339   const char shortcuts_fr_string[]="Raccourcis clavier (shell et editeur)\nlivre: aide/complete\ntab: complete (shell)/indente (editeur)\nshift-/: %\nshift *: '\nctrl-/: \\\nshift-1 a 6: selon bandeau en bas\nshift-7: matrices\nshift-8: listes\nshift-9:arithmetique\nshift-0: complexes\nshift-.: reels\nctrl P: programme\nvar: liste des variables (shell) ou dessin tortue (editeur)\n\nctrl-var (sto) renvoie =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: Editeur 2d ou graphique ou texte selon objet\nshift-4: editeur texte\n+ ou - modifie un parametre en surbrillance\n\nEditeur d'expressions\nctrl z: defaire/refaire (1 fois)\npave directionnel: deplace la selection dans l'arborescence de l'expression\nshift-droit/gauche echange selection avec argument a droite ou a gauche\nctrl droit/gauche dans une somme ou un produit: augmente la selection avec argument droit ou gauche\nshift-4: Editer selection, shift-5: taille police + ou - grande\nenter: evaluer la selection\nshift-6: valeur approchee\nDel: supprime l'operateur racine de la selection\n\nEditeur de scripts\nenter: passage a la ligne\nctrl z: defaire/refaire (1 fois)\nctrl c: marque le debut de la selection, deplacer le curseur vers la fin puis Del pour effacer ou ctrl c pour copier sans effacer. ctrl v pour coller.\nMenu-6 recherche seule: entrer un mot puis enter puis enter. Taper enter pour l'occurence suivante, esc pour annuler.\nMenu-6 remplacer: entrer un mot puis enter puis le remplacement et enter. Taper enter ou esc pour remplacer ou non et passer a l'occurence suivante, ctrl del pour annuler\nvalidation (a droite de U): tester syntaxe\n\nRaccourcis Graphes:\n+ - zoom\n(-): zoomout selon y\n*: autoscale\n/: orthonormalisation\nOPTN: axes on/off";
1340   const char shortcuts_en_string[]="Keyboard shortcuts (shell and editor)\nbook: help or completion\ntab: completion (shell), indent (editor)\nshift-/: %\nalpha shift *: '\nctrl-/: \\\nshift-1 a 6: see at bottom\nshift-7: matrices\nshift-8: listes\nshift-9:arithmetic\nshift-0: complexes\nshift-.: reals\nctrl P: program\nvar: variables list (shell) or turtle screen (editor)\n\nctrl var (sto) returns =>\n=>+: partfrac\n=>*: factor\n=>sin/cos/tan\n=>=>: solve\n\nShell:\nshift-5: 2d editor or graph or text\nshift-4: text edit\n+ ou - modifies selected slider\n\nExpressions editor\nctrl z: undo/redo (1 fois)\nkeypad: move selection inside expression tree\nshift-right/left exchange selection with right or left argument\nalpha-right/left: inside a sum or product: increase selection with right or left argument\nshift-4: Edit selection, shift-5: change fontsize\nenter: eval selection\nshift-6: approx value\nDel: suppress selection's rootnode operator\n\nScript Editor\nenter: newline\nctrl z: undo/redo (1 time)\nctrl c: marks selection begin, move the cursor to the end, then hit Del to erase or ctrl c to copy (no erase). ctrl v to paste.\nMenu-6 search: enter a word then enter then again enter. Type enter for next occurence, esc to cancel.\nMenu-6 replace: enter a word then enter then replacement word then enter. Type enter or esc to replace or ignore and go to next occurence, AC to cancel\nOK: test syntax\n\nGraph shortcuts:\n+ - zoom\n(-): zoomout along y\n*: autoscale\n/: orthonormalization\nOPTN: axes on/off";
1341 #endif
1342 
1343   const char apropos_fr_string[]="Giac/Xcas 1.6.0, (c) 2020 B. Parisse et R. De Graeve, www-fourier.univ-grenoble-alpes.fr/~parisse.\nKhicas, interface pour calculatrices par B. Parisse, license GPL version 2, adaptee de l'interface d'Eigenmath pour Casio, G. Maia (http://gbl08ma.com), Mike Smith, Nemhardy, LePhenixNoir, ...\nPortage sur Numworks par Damien Nicolet. Remerciements a Jean-Baptiste Boric et Maxime Friess\nPortage sur Nspire grace a Fabian Vogt (firebird-emu, ndless...).\nTable periodique d'apres Maxime Friess\nRemerciements au site tiplanet, en particulier Xavier Andreani, Adrien Bertrand, Lionel Debroux";
1344 
1345   const char apropos_en_string[]="Giac/Xcas 1.6.0, (c) 2020 B. Parisse et R. De Graeve, www-fourier.univ-grenoble-alpes.fr/~parisse.\nKhicas, calculators interface by B. Parisse, GPL license version 2, adapted from Eigenmath for Casio, G. Maia (http://gbl08ma.com), Mike Smith, Nemhardy, LePhenixNoir, ...\nPorted on Numworks by Damien Nicolet. Thanks to Jean-Baptiste Boric and Maxime Friess\nPorted on Nspire thanks to Fabian Vogt (firebird-emu, ndless...)\nPeriodic table by Maxime Friess\nThanks to tiplanet, especially Xavier Andreani, Adrien Bertrand, Lionel Debroux";
1346 
1347   const int CAT_COMPLETE_COUNT_FR=sizeof(completeCatfr)/sizeof(catalogFunc);
1348   const int CAT_COMPLETE_COUNT_EN=sizeof(completeCaten)/sizeof(catalogFunc);
1349 
insert_string(int index)1350   std::string insert_string(int index){
1351     std::string s;
1352     const catalogFunc * completeCat=(lang==1)?completeCatfr:completeCaten;
1353     if (completeCat[index].insert)
1354       s=completeCat[index].insert;
1355     else {
1356       s=completeCat[index].name;
1357       int pos=s.find('(');
1358       if (pos>=0 && pos<s.size())
1359 	s=s.substr(0,pos+1);
1360     }
1361     return s;//s+' ';
1362   }
1363 
1364   // not tested
aide2catalogFunc(const giac::aide & a,catalogFunc & c)1365   void aide2catalogFunc(const giac::aide & a,catalogFunc & c){
1366     static aide as=a;
1367     static string desc;
1368     string descrip;
1369     c.name=as.cmd_name.c_str();
1370     c.insert=c.name;
1371     desc=as.syntax+'\n';
1372     for (int i=0;i<as.blabla.size();++i){
1373       localized_string & ls=as.blabla[i];
1374       if (ls.language==lang){ // exact match
1375 	descrip=as.blabla[i].chaine.c_str();
1376 	break;
1377       }
1378       if (ls.language==0) // default
1379 	descrip=as.blabla[i].chaine.c_str();
1380     }
1381     desc += descrip;
1382     c.desc=desc.c_str();
1383     c.example=as.examples.size()?as.examples[0].c_str():0;
1384     c.example2=as.examples.size()>=2?as.examples[1].c_str():0;
1385     c.category=-1;
1386   }
showCatalog(char * insertText,int preselect,int menupos,GIAC_CONTEXT)1387   int showCatalog(char* insertText,int preselect,int menupos,GIAC_CONTEXT) {
1388     // returns 0 on failure (user exit) and 1 on success (user chose a option)
1389     MenuItem menuitems[CAT_CATEGORY_LOGO+1];
1390     menuitems[CAT_CATEGORY_ALL].text = (char*)((lang==1)?"Tout":"All");
1391     menuitems[CAT_CATEGORY_ALGEBRA].text = (char*)((lang==1)?"Algebre":"Algebra");
1392     menuitems[CAT_CATEGORY_LINALG].text = (char*)((lang==1)?"Algebre lineaire":"Linear algebra");
1393     menuitems[CAT_CATEGORY_CALCULUS].text = (char*)((lang==1)?"Analyse":"Calculus");
1394     menuitems[CAT_CATEGORY_ARIT].text = (char*)"Arithmetic, crypto";
1395     menuitems[CAT_CATEGORY_COMPLEXNUM].text = (char*)"Complexes";
1396     menuitems[CAT_CATEGORY_PLOT].text = (char*)((lang==1)?"Courbes":"Curves");
1397     menuitems[CAT_CATEGORY_POLYNOMIAL].text = (char*)((lang==1)?"Polynomes":"Polynomials");
1398     menuitems[CAT_CATEGORY_PROBA].text = (char*)((lang==1)?"Probabilites":"Probabilities");
1399     menuitems[CAT_CATEGORY_PROGCMD].text = (char*)((lang==1)?"Programmes cmds (0)":"Program cmds (0)");
1400     menuitems[CAT_CATEGORY_REAL].text = (char*)((lang==1)?"Reels (e^)":"Reals");
1401     menuitems[CAT_CATEGORY_SOLVE].text = (char*)((lang==1)?"Resoudre (ln)":"Solve (ln)");
1402     menuitems[CAT_CATEGORY_STATS].text = (char*)((lang==1)?"Statistiques (log)":"Statistics (log)");
1403     menuitems[CAT_CATEGORY_TRIG].text = (char*)((lang==1)?"Trigonometrie (i)":"Trigonometry (i)");
1404     menuitems[CAT_CATEGORY_OPTIONS].text = (char*)"Options (,)";
1405     menuitems[CAT_CATEGORY_LIST].text = (char*)((lang==1)?"Listes (x^y)":"Lists (x^y)");
1406     menuitems[CAT_CATEGORY_MATRIX].text = (char*)"Matrices (sin)";
1407     menuitems[CAT_CATEGORY_PROG].text = (char*)((lang==1)?"Programmes (cos)":"Programs");
1408     menuitems[CAT_CATEGORY_SOFUS].text = (char*)((lang==1)?"Modifier variables (tan)":"Change variables (tan)");
1409     menuitems[CAT_CATEGORY_PHYS].text = (char*)((lang==1)?"Constantes physique (pi)":"Physics constants (pi)");
1410     menuitems[CAT_CATEGORY_UNIT].text = (char*)((lang==1)?"Unites physiques (sqrt)":"Units (sqrt)");
1411     menuitems[CAT_CATEGORY_LOGO].text = (char*)((lang==1)?"Tortue (x^2)":"Turtle (x^2)");
1412 
1413     Menu menu;
1414     menu.items=menuitems;
1415     menu.numitems=sizeof(menuitems)/sizeof(MenuItem);
1416     menu.scrollout=1;
1417     menu.title = (char*)((lang==1)?"Liste de commandes":"Commands list");
1418     //puts("catalog 1");
1419     while(1) {
1420       if (preselect)
1421 	menu.selection=preselect;
1422       else {
1423 	if (menupos>0)
1424 	  menu.selection=menupos;
1425 	int sres = doMenu(&menu);
1426 	if (sres != MENU_RETURN_SELECTION && sres!=KEY_CTRL_EXE)
1427 	  return 0;
1428       }
1429       // puts("catalog 3");
1430       if(doCatalogMenu(insertText, menuitems[menu.selection-1].text, menu.selection-1,contextptr))
1431 	return 1;
1432       if (preselect)
1433 	return 0;
1434     }
1435     return 0;
1436   }
1437 
showCatalog(char * text,int nmenu,GIAC_CONTEXT)1438   int showCatalog(char * text,int nmenu,GIAC_CONTEXT){
1439     return showCatalog(text,0,nmenu,contextptr);
1440   }
1441 
isalphanum(char c)1442   bool isalphanum(char c){
1443     return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
1444   }
1445 
help_insert(const char * cmdline,GIAC_CONTEXT)1446   string help_insert(const char * cmdline,GIAC_CONTEXT){
1447     int l=strlen(cmdline);
1448     char buf[l+1];
1449     strcpy(buf,cmdline);
1450     bool openpar=l && buf[l-1]=='(';
1451     if (openpar){
1452       buf[l-1]=0;
1453       --l;
1454     }
1455     for (;l>0;--l){
1456       if (!isalphanum(buf[l-1]) && buf[l-1]!='_')
1457 	break;
1458     }
1459     // cmdname in buf+l
1460     const char * cmdname=buf+l,*cmdnameorig=cmdname;
1461     l=strlen(cmdname);
1462     // search in catalog: dichotomy would be more efficient
1463     // but leading spaces cmdnames would be missed
1464     int nfunc=(lang==1)?CAT_COMPLETE_COUNT_FR:CAT_COMPLETE_COUNT_EN;//sizeof(completeCat)/sizeof(catalogFunc);
1465 #ifdef NSPIRE_NEWLIB
1466     int iii=nfunc; // no search in completeCat, directly in static_help.h
1467 #else
1468     int iii=0;
1469 #endif
1470     const catalogFunc * completeCat=(lang==1)?completeCatfr:completeCaten;
1471     for (;iii<nfunc;++iii){
1472       const char * name=completeCat[iii].name;
1473       while (*name==' ')
1474 	++name;
1475       int j=0;
1476       for (;j<l;++j){
1477 	if (name[j]!=cmdname[j])
1478 	  break;
1479       }
1480       if (j==l)
1481 	break;
1482     }
1483     const catalogFunc * catf=iii==nfunc?0:completeCat+iii;
1484     const char * fhowto=0,* fsyntax=0,* frelated=0,* fexamples=0;
1485     char fbuf[1024];
1486     if (iii==nfunc){
1487       if (!has_static_help(cmdname,lang,fhowto,fsyntax,fexamples,frelated)){
1488 	confirm("Pas d'aide disponible pour",cmdname,true);
1489 	return "";
1490       }
1491       if (fexamples && fexamples[0]==0){
1492 	fexamples=frelated;
1493 	frelated=0;
1494       }
1495       // cut example at ; if there is one
1496       for (int i=0;i<sizeof(fbuf);++i){
1497 	if (fexamples[i]==0)
1498 	  break;
1499 	if (fexamples[i]==';'){
1500 	  strcpy(fbuf,fexamples);
1501 	  fbuf[i]=0;
1502 	  fexamples=fbuf;
1503 	  frelated=fbuf+i+1;
1504 	  while (*frelated==' ')
1505 	    ++frelated;
1506 	  for (++i;i<sizeof(fbuf);++i){
1507 	    if (fbuf[i]==0)
1508 	      break;
1509 	    if (fbuf[i]==';'){
1510 	      fbuf[i]=0;
1511 	      break;
1512 	    }
1513 	  }
1514 	  break;
1515 	}
1516       }
1517     }
1518     const char * example=catf?catf->example:fexamples;
1519     const char * example2=catf?catf->example2:frelated;
1520     xcas::textArea text;
1521     text.editable=false;
1522     text.clipline=-1;
1523     text.title = (char*)((lang==1)?"Aide sur la commande":"Help on command");
1524     text.allowF1=true;
1525     text.python=false;
1526     std::vector<xcas::textElement> & elem=text.elements;
1527     elem = std::vector<xcas::textElement> (example2?4:3);
1528     elem[0].s = catf?catf->name:cmdname;
1529     elem[0].newLine = 0;
1530     //elem[0].color = COLOR_BLUE;
1531     elem[1].newLine = 1;
1532     elem[1].lineSpacing = 1;
1533     elem[1].minimini=1;
1534     std::string autoexample;
1535     if (catf && catf->desc==0){
1536       // if (token==T_UNARY_OP || token==T_UNARY_OP_38)
1537       elem[1].s=elem[0].s+"(args)";
1538     }
1539     else
1540       elem[1].s = catf?catf->desc:fhowto;
1541 #ifdef NSPIRE_NEWLIB
1542     std::string ex("tab: ");
1543 #else
1544     std::string ex("Ans: ");
1545 #endif
1546     elem[2].newLine = 1;
1547     elem[2].lineSpacing = 0;
1548     //elem[2].minimini=1;
1549     if (example){
1550       if (example[0]=='#')
1551 	ex += example+1;
1552       else {
1553 	if (iii==nfunc)
1554 	  ex += fexamples;
1555 	else {
1556 	  ex += insert_string(iii);
1557 	  ex += example;
1558 	  ex += ")";
1559 	}
1560       }
1561       elem[2].s = ex;
1562       if (example2){
1563 #ifdef NSPIRE_NEWLIB
1564 	string ex2="ret: ";
1565 #else
1566 	string ex2="EXE: ";
1567 #endif
1568 	if (example2[0]=='#')
1569 	  ex2 += example2+1;
1570 	else {
1571 	  if (iii==nfunc)
1572 	    ex2 += example2;
1573 	  else {
1574 	    ex2 += insert_string(iii);
1575 	    ex2 += example2;
1576 	    ex2 += ")";
1577 	  }
1578 	}
1579 	elem[3].newLine = 1;
1580 	// elem[3].lineSpacing = 0;
1581 	//elem[3].minimini=1;
1582 	elem[3].s=ex2;
1583       }
1584     }
1585     else {
1586       if (autoexample.size())
1587 	elem[2].s=ex+autoexample;
1588       else
1589 	elem.pop_back();
1590     }
1591     int sres=doTextArea(&text,contextptr);
1592     if (sres==KEY_SHUTDOWN)
1593       return "";
1594     if (sres==MENU_RETURN_SELECTION){
1595       while (*cmdname && *cmdname==*cmdnameorig){
1596 	++cmdname; ++cmdnameorig;
1597       }
1598       return cmdname;
1599     }
1600     if (sres == KEY_CHAR_ANS || sres==KEY_BOOK || sres=='\t' || sres==KEY_CTRL_EXE) {
1601       reset_kbd();
1602       std::string s;
1603       const char * example=0;
1604       if (sres==KEY_CHAR_ANS || sres==KEY_BOOK || sres=='\t')
1605 	example=catf?catf->example:fexamples;
1606       else
1607 	example=catf?catf->example2:frelated;
1608       if (example){
1609 	while (*example && *example==*cmdnameorig){
1610 	  ++example; ++cmdnameorig;
1611 	}
1612 	if (openpar && example[0]=='(')
1613 	  ++example;
1614 	if (example[0]=='#')
1615 	  s=example+1;
1616 	else {
1617 	  s += example;
1618 	  //if (catf && s[s.size()-1]!=')') s += ")";
1619 	}
1620       }
1621       return s;
1622     }
1623     return "";
1624   }
1625 
1626   // 0 on exit, 1 on success
doCatalogMenu(char * insertText,const char * title,int category,GIAC_CONTEXT)1627   int doCatalogMenu(char* insertText, const char* title, int category,GIAC_CONTEXT) {
1628     const catalogFunc * completeCat=(lang==1)?completeCatfr:completeCaten;
1629     for (;;){
1630       int allcmds=builtin_lexer_functions_end()-builtin_lexer_functions_begin();
1631       int allopts=lexer_tab_int_values_end-lexer_tab_int_values_begin;
1632       bool isall=category==CAT_CATEGORY_ALL;
1633       bool isopt=category==CAT_CATEGORY_OPTIONS;
1634       const int CAT_COMPLETE_COUNT=((lang==1)?CAT_COMPLETE_COUNT_FR:CAT_COMPLETE_COUNT_EN);
1635       int nitems = isall? allcmds:(isopt?allopts:CAT_COMPLETE_COUNT);
1636 #ifdef MENUITEM_MALLOC
1637       MenuItem *menuitems=(MenuItem *) malloc(sizeof(MenuItem)*nitems);
1638       if (!menuitems)
1639 	return 0;
1640 #else
1641       MenuItem menuitems[nitems];
1642 #endif
1643       int cur = 0,curmi = 0,i=0;
1644       gen g;
1645       while(cur<nitems) {
1646 	menuitems[curmi].type = MENUITEM_NORMAL;
1647 	menuitems[curmi].color = _BLACK;
1648 	if (isall || isopt) {
1649 	  const char * text=isall?(builtin_lexer_functions_begin()+curmi)->first:(lexer_tab_int_values_begin+curmi)->keyword;
1650 	  menuitems[curmi].text = (char*) text;
1651 	  menuitems[curmi].isfolder = allcmds; // assumes allcmds>allopts
1652 	  menuitems[curmi].token=isall?((builtin_lexer_functions_begin()+curmi)->second.subtype+256):((lexer_tab_int_values_begin+curmi)->subtype+(lexer_tab_int_values_begin+curmi)->return_value*256);
1653 	  // menuitems[curmi].token=isall?find_or_make_symbol(text,g,0,false,contextptr):((lexer_tab_int_values_begin+curmi)->subtype+(lexer_tab_int_values_begin+curmi)->return_value*256);
1654 	  for (;i<CAT_COMPLETE_COUNT;++i){
1655 	    const char * catname=completeCat[i].name;
1656 	    int tmp=strcmp(catname,text);
1657 	    if (tmp>=0){
1658 	      size_t st=strlen(text),j=tmp?0:st;
1659 	      for (;j<st;++j){
1660 		if (catname[j]!=text[j])
1661 		  break;
1662 	      }
1663 	      if (j==st && (!isalphanum(catname[j]))){
1664 		menuitems[curmi].isfolder = i;
1665 		++i;
1666 	      }
1667 	      break;
1668 	    }
1669 	  }
1670 	  // compare text with completeCat
1671 	  ++curmi;
1672 	}
1673 	else {
1674 	  int cat=completeCat[cur].category;
1675 	  if ( (cat & 0xff) == category ||
1676 	       (cat & 0xff00) == (category<<8) ||
1677 	       (cat & 0xff0000) == (category <<16)
1678 	       ){
1679 	    menuitems[curmi].isfolder = cur; // little hack: store index of the command in the full list in the isfolder property (unused by the menu system in this case)
1680 	    menuitems[curmi].text = (char *) completeCat[cur].name;
1681 	    curmi++;
1682 	  }
1683 	}
1684 	cur++;
1685       }
1686 
1687       Menu menu;
1688       menu.items=menuitems;
1689       menu.numitems=curmi;
1690       if (isopt){ menu.selection=5; menu.scroll=4; }
1691       if (curmi>=100)
1692 	lock_alpha(); //SetSetupSetting( (unsigned int)0x14, 0x88);
1693       // DisplayStatusArea();
1694       menu.scrollout=1;
1695       menu.title = (char *) title;
1696       menu.type = MENUTYPE_FKEYS;
1697       menu.height = 11;
1698       while(1) {
1699 	drawRectangle(0,200,LCD_WIDTH_PX,22,giac::_WHITE);
1700 #ifdef NSPIRE_NEWLIB
1701 	PrintMini(0,200,(category==CAT_CATEGORY_ALL?"doc: help | tab: ex1 | enter: ex2":"doc: help | tab: ex1 | enter ex2"),4,33333,giac::_WHITE);
1702 #else
1703 	PrintMini(0,200,(category==CAT_CATEGORY_ALL?"Toolbox help | Ans ex1 | EXE  ex2":"Toolbox help | Ans ex1 | EXE ex2"),4,33333,giac::_WHITE);
1704 #endif
1705 	int sres = doMenu(&menu);
1706 	if (sres==KEY_CTRL_F4 && category!=CAT_CATEGORY_ALL){
1707 	  break;
1708 	}
1709 	if(sres == MENU_RETURN_EXIT){
1710 	  reset_kbd();
1711 #ifdef MENUITEM_MALLOC
1712 	  free(menuitems);
1713 #endif
1714 	  return sres;
1715 	}
1716 	int index=menuitems[menu.selection-1].isfolder;
1717 	if(sres == KEY_CTRL_CATALOG || sres==KEY_BOOK) {
1718 	  const char * example=index<allcmds?completeCat[index].example:0;
1719 	  const char * example2=index<allcmds?completeCat[index].example2:0;
1720 	  xcas::textArea text;
1721 	  text.editable=false;
1722 	  text.clipline=-1;
1723 	  text.title = (char*)((lang==1)?"Aide sur la commande":"Help on command");
1724 	  text.allowF1=true;
1725 	  text.python=python_compat(contextptr);
1726 	  std::vector<xcas::textElement> & elem=text.elements;
1727 	  elem = std::vector<xcas::textElement> (example2?4:3);
1728 	  elem[0].s = index<allcmds?completeCat[index].name:menuitems[menu.selection-1].text;
1729 	  elem[0].newLine = 0;
1730 	  //elem[0].color = COLOR_BLUE;
1731 	  elem[1].newLine = 1;
1732 	  elem[1].lineSpacing = 1;
1733 	  elem[1].minimini=1;
1734 	  std::string autoexample;
1735 	  if (index<allcmds)
1736 	    elem[1].s = completeCat[index].desc;
1737 	  else {
1738 	    int token=menuitems[menu.selection-1].token;
1739 	    elem[1].s="Desole, pas d'aide disponible...";
1740 	    const char *fcmdname=menuitems[menu.selection-1].text,* fhowto=0,*fsyntax=0,*fexamples=0,*frelated=0;
1741 	    if (has_static_help(fcmdname,lang,fhowto,fsyntax,fexamples,frelated)){
1742 	      elem[1].s=fhowto;
1743 	      example=fexamples;
1744 	    }
1745 	    else {
1746 	      // *logptr(contextptr) << token << endl;
1747 	      if (isopt){
1748 		if (token==_INT_PLOT+T_NUMBER*256){
1749 		  autoexample="display="+elem[0].s;
1750 		  elem[1].s ="Option d'affichage: "+ autoexample;
1751 		}
1752 		if (token==_INT_COLOR+T_NUMBER*256){
1753 		  autoexample="display="+elem[0].s;
1754 		  elem[1].s="Option de couleur: "+ autoexample;
1755 		}
1756 		if (token==_INT_SOLVER+T_NUMBER*256){
1757 		  autoexample=elem[0].s;
1758 		  elem[1].s="Option de fsolve: " + autoexample;
1759 		}
1760 		if (token==_INT_TYPE+T_TYPE_ID*256){
1761 		  autoexample=elem[0].s;
1762 		  elem[1].s="Type d'objet: " + autoexample;
1763 		}
1764 	      }
1765 	      if (isall){
1766 		if (token==T_UNARY_OP || token==T_UNARY_OP_38)
1767 		  elem[1].s=elem[0].s+"(args)";
1768 	      }
1769 	    }
1770 	  }
1771 #ifdef NSPIRE_NEWLIB
1772 	  std::string ex("tab: ");
1773 #else
1774 	  std::string ex("Ans: ");
1775 #endif
1776 	  elem[2].newLine = 1;
1777 	  elem[2].lineSpacing = 0;
1778 	  //elem[2].minimini=1;
1779 	  if (example){
1780 	    if (example[0]=='#')
1781 	      ex += example+1;
1782 	    else {
1783 	      if (index<allcmds){
1784 		ex += insert_string(index);
1785 		ex += example;
1786 		ex += ")";
1787 	      }
1788 	      else ex+=example;
1789 	    }
1790 	    elem[2].s = ex;
1791 	    if (example2){
1792 #ifdef NSPIRE_NEWLIB
1793 	      string ex2="enter: ";
1794 #else
1795 	      string ex2="EXE: ";
1796 #endif
1797 	      if (example2[0]=='#')
1798 		ex2 += example2+1;
1799 	      else {
1800 		if (index<allcmds){
1801 		  ex2 += insert_string(index);
1802 		  ex2 += example2;
1803 		  ex2 += ")";
1804 		}
1805 		else
1806 		  ex2 += example2;
1807 	      }
1808 	      elem[3].newLine = 1;
1809 	      // elem[3].lineSpacing = 0;
1810 	      //elem[3].minimini=1;
1811 	      elem[3].s=ex2;
1812 	    }
1813 	  }
1814 	  else {
1815 	    if (autoexample.size())
1816 	      elem[2].s=ex+autoexample;
1817 	    else
1818 	      elem.pop_back();
1819 	  }
1820 	  sres=doTextArea(&text,contextptr);
1821 	}
1822 	if (sres == KEY_CHAR_ANS || sres=='\t' ||sres==KEY_BOOK || sres==KEY_CTRL_EXE) {
1823 	  reset_kbd();
1824 	  const char * example=0;
1825 	  std::string s;
1826 	  if (index<allcmds ){
1827 	    s=insert_string(index);
1828 	    if (sres==KEY_CHAR_ANS || sres=='\t' || sres==KEY_BOOK)
1829 	      example=completeCat[index].example;
1830 	    else
1831 	      example=completeCat[index].example2;
1832 	  }
1833 	  else {
1834 	    const char *fcmdname=menuitems[menu.selection-1].text,* fhowto=0,*fsyntax=0,*fexamples=0,*frelated=0;
1835 	    if (has_static_help(fcmdname,lang,fhowto,fsyntax,fexamples,frelated)){
1836 	      example=fexamples;
1837 	    }
1838 	  }
1839 	  if (example){
1840 	    if (example[0]=='#')
1841 	      s=example+1;
1842 	    else {
1843 	      s += example;
1844 	      if (s[s.size()-1]!=')')
1845 		s += ")";
1846 	    }
1847 	    strcpy(insertText, s.c_str());
1848 #ifdef MENUITEM_MALLOC
1849 	    free(menuitems);
1850 #endif
1851 	    return 1;
1852 	  }
1853 	  else {
1854 	    if (isopt){
1855 	      int token=menuitems[menu.selection-1].token;
1856 	      if (token==_INT_PLOT+T_NUMBER*256 || token==_INT_COLOR+T_NUMBER*256)
1857 		strcpy(insertText,"display=");
1858 	      else
1859 		*insertText=0;
1860 	      strcat(insertText,menuitems[menu.selection-1].text);
1861 #ifdef MENUITEM_MALLOC
1862 	      free(menuitems);
1863 #endif
1864 	      return 1;
1865 	    }
1866 	  }
1867 	  sres=KEY_CTRL_OK;
1868 	}
1869 	if(sres == MENU_RETURN_SELECTION || sres == KEY_CTRL_OK) {
1870 	  reset_kbd();
1871 	  strcpy(insertText,index<allcmds?insert_string(index).c_str():menuitems[menu.selection-1].text);
1872 #ifdef MENUITEM_MALLOC
1873 	  free(menuitems);
1874 #endif
1875 	  return 1;
1876 	}
1877       }
1878       title="CATALOG";
1879       category=0;
1880     } // end endless for
1881     return 0;
1882   }
1883 
select_var(GIAC_CONTEXT)1884   gen select_var(GIAC_CONTEXT){
1885     kbd_interrupted=giac::ctrl_c=giac::interrupted=false;
1886 #ifdef MICROPY_LIB
1887     if (xcas_python_eval==1){
1888       const char ** tab=(const char **)mp_vars();
1889       if (tab){
1890 	int i=select_item(tab,"VARS",true);
1891 	gen g=undef;
1892 	if (i>=0 && tab[i])
1893 	  g=gen(tab[i],contextptr);
1894 	free(tab);
1895 	return g;
1896       }
1897     }
1898 #endif
1899     gen g(_VARS(0,contextptr));
1900     if (g.type!=_VECT || g._VECTptr->empty()){
1901       confirm((lang==1)?"Pas de variables. Exemples pour en creer":"No variables. Examples to create",(lang==1)?"a=1 ou f(x):=sin(x^2)":"a=1 or f(x):=sin(x^2)",true);
1902       return undef;
1903     }
1904     vecteur & v=*g._VECTptr;
1905     MenuItem smallmenuitems[v.size()+3];
1906     vector<std::string> vs(v.size()+1);
1907     int i,total=0;
1908     const char typ[]="idzDcpiveSfEsFRmuMwgPF";
1909     for (i=0;i<v.size();++i){
1910       vs[i]=v[i].print(contextptr);
1911       if (v[i].type==giac::_IDNT){
1912 	giac::gen w;
1913 	v[i]._IDNTptr->in_eval(0,v[i],w,contextptr,true);
1914 #if 1
1915 	vector<int> vi(9);
1916 	tailles(w,vi);
1917 	total += vi[8];
1918 	if (vi[8]<400)
1919 	  vs[i]+=":="+w.print(contextptr);
1920 	else {
1921 	  vs[i] += " ~";
1922 	  vs[i] += giac::print_INT_(vi[8]);
1923 	  vs[i] += ',';
1924 	  vs[i] += typ[w.type];
1925 	}
1926 #else
1927 	if (taille(w,50)<50)
1928 	  vs[i]+=": "+w.print(contextptr);
1929 #endif
1930       }
1931       smallmenuitems[i].text=(char *) vs[i].c_str();
1932     }
1933     total +=
1934       // giac::syms().capacity()*(sizeof(string)+sizeof(giac::gen)+8)+sizeof(giac::sym_string_tab) +
1935       giac::turtle_stack().capacity()*sizeof(giac::logo_turtle) +
1936       // sizeof(giac::context)+contextptr->tabptr->capacity()*(sizeof(const char *)+sizeof(giac::gen)+8)+
1937       bytesize(giac::history_in(contextptr))+bytesize(giac::history_out(contextptr));
1938     vs[i]="purge(~"+giac::print_INT_(total)+')';
1939     smallmenuitems[i].text=(char *)vs[i].c_str();
1940     smallmenuitems[i+1].text=(char *)"assume(";
1941     smallmenuitems[i+2].text=(char *)"restart";
1942     Menu smallmenu;
1943     smallmenu.numitems=v.size()+3;
1944     smallmenu.items=smallmenuitems;
1945     smallmenu.height=12;
1946     smallmenu.scrollbar=1;
1947     smallmenu.scrollout=1;
1948     smallmenu.title = (char*)"Variables";
1949     //MsgBoxPush(5);
1950     int sres = doMenu(&smallmenu);
1951     //MsgBoxPop();
1952     if (sres==KEY_CTRL_DEL && smallmenu.selection<=v.size())
1953       return symbolic(at_purge,v[smallmenu.selection-1]);
1954     if (sres!=MENU_RETURN_SELECTION && sres!=KEY_CTRL_EXE)
1955       return undef;
1956     if (smallmenu.selection==1+v.size())
1957       return string2gen("purge(",false);
1958     if (smallmenu.selection==2+v.size())
1959       return string2gen("assume(",false);
1960     if (smallmenu.selection==3+v.size())
1961       return string2gen("restart",false);
1962     return v[smallmenu.selection-1];
1963   }
1964 
keytostring(int key,int keyflag,bool py,const giac::context * contextptr)1965   const char * keytostring(int key,int keyflag,bool py,const giac::context * contextptr){
1966     const int textsize=512;
1967     static char text[textsize];
1968     if (key>=0x20 && key<=0x7e){
1969       text[0]=key;
1970       text[1]=0;
1971       return text;
1972     }
1973     switch (key){
1974     case KEY_CHAR_PLUS:
1975       return "+";
1976     case KEY_CHAR_MINUS:
1977       return "-";
1978     case KEY_CHAR_PMINUS:
1979       return "_";
1980     case KEY_CHAR_MULT:
1981       return "*";
1982     case KEY_CHAR_FRAC:
1983       return py?"\\":"solve(";
1984     case KEY_CHAR_DIV:
1985       return "/";
1986     case KEY_CHAR_POW:
1987       return "^";
1988     case KEY_CHAR_ROOT:
1989       return "sqrt(";
1990     case KEY_CHAR_SQUARE:
1991       return py?"**2":"^2";
1992     case KEY_CHAR_CUBEROOT:
1993       return py?"**(1/3)":"^(1/3)";
1994     case KEY_CHAR_POWROOT:
1995       return py?"**(1/":"^(1/";
1996     case KEY_CHAR_RECIP:
1997       return py?"**-1":"^-1";
1998     case KEY_CHAR_THETA:
1999       return "arg(";
2000     case KEY_CHAR_VALR:
2001       return "abs(";
2002     case KEY_CHAR_ANGLE:
2003       return "polar_complex(";
2004     case KEY_CTRL_XTT:
2005       return xthetat?"t":"x";
2006     case KEY_CHAR_LN:
2007       return "ln(";
2008     case KEY_CHAR_LOG:
2009       return "log10(";
2010     case KEY_CHAR_EXPN10:
2011       return "10^";
2012     case KEY_CHAR_EXPN:
2013       return "exp(";
2014     case KEY_CHAR_SIN:
2015       return "sin(";
2016     case KEY_CHAR_COS:
2017       return "cos(";
2018     case KEY_CHAR_TAN:
2019       return "tan(";
2020     case KEY_CHAR_ASIN:
2021       return "asin(";
2022     case KEY_CHAR_ACOS:
2023       return "acos(";
2024     case KEY_CHAR_ATAN:
2025       return "atan(";
2026     case KEY_CTRL_MIXEDFRAC:
2027       return "limit(";
2028     case KEY_CTRL_FRACCNVRT:
2029       return "exact(";
2030       // case KEY_CTRL_FORMAT: return "purge(";
2031     case KEY_CTRL_FD:
2032       return "approx(";
2033     case KEY_CHAR_STORE:
2034       // if (keyflag==1) return "inf";
2035       return "=>";
2036     case KEY_CHAR_IMGNRY:
2037       return "i";
2038     case KEY_CHAR_PI:
2039       return "pi";
2040     case KEY_CTRL_VARS: {
2041       giac::gen var=select_var(contextptr);
2042       if (!giac::is_undef(var)){
2043 	strcpy(text,(var.type==giac::_STRNG?*var._STRNGptr:var.print(contextptr)).c_str());
2044 	return text;
2045       }
2046       return "";//"VARS()";
2047     }
2048     case KEY_CHAR_EXP:
2049       return "e";
2050     case KEY_CHAR_ANS:
2051       return "ans()";
2052     case KEY_CTRL_INS:
2053       return ":=";
2054     case KEY_CHAR_MAT:{
2055       const char * ptr=xcas::input_matrix(false,contextptr); if (ptr) return ptr;
2056       if (showCatalog(text,17,contextptr)) return text;
2057       return "";
2058     }
2059     case KEY_CHAR_LIST: {
2060       const char * ptr=xcas::input_matrix(true,contextptr); if (ptr) return ptr;
2061       if (showCatalog(text,16,contextptr)) return text;
2062       return "";
2063     }
2064     case KEY_CTRL_PRGM:
2065       // open functions catalog, prgm submenu
2066       if(showCatalog(text,18,contextptr))
2067 	return text;
2068       return "";
2069     case KEY_CTRL_CATALOG: case KEY_BOOK:
2070       if(showCatalog(text,0,contextptr))
2071 	return text;
2072       return "";
2073     case KEY_CTRL_F4:
2074       if(showCatalog(text,0,contextptr))
2075 	return text;
2076       return "";
2077     case KEY_CTRL_OPTN:
2078       if(showCatalog(text,15,contextptr))
2079 	return text;
2080       return "";
2081     case KEY_CTRL_QUIT:
2082       if(showCatalog(text,20,contextptr))
2083 	return text;
2084       return "";
2085     case KEY_CTRL_PASTE:
2086       return paste_clipboard();
2087     case KEY_CHAR_DQUATE:
2088       return "\"";
2089     case KEY_CHAR_FACTOR:
2090       return "factor(";
2091     case KEY_CHAR_NORMAL:
2092       return "normal(";
2093     }
2094     return 0;
2095   }
2096 
keytostring(int key,int keyflag,GIAC_CONTEXT)2097   const char * keytostring(int key,int keyflag,GIAC_CONTEXT){
2098     return keytostring(key,keyflag,python_compat(contextptr),contextptr);
2099   }
2100 
stringtodouble(const string & s1,double & d)2101   bool stringtodouble(const string & s1,double & d){
2102     gen g(s1,context0);
2103     g=evalf(g,1,context0);
2104     if (g.type!=_DOUBLE_){
2105       confirm("Invalid value",s1.c_str());
2106       return false;
2107     }
2108     d=g._DOUBLE_val;
2109     return true;
2110   }
2111 
inputdouble(const char * msg1,double & d,GIAC_CONTEXT)2112   bool inputdouble(const char * msg1,double & d,GIAC_CONTEXT){
2113     int di=d;
2114     string s1;
2115     if (di==d)
2116       s1=print_INT_(di);
2117     else
2118       s1=print_DOUBLE_(d,3);
2119     inputline(msg1,((lang==1)?"Nouvelle valeur? ":"New value? "),s1,false,65,contextptr);
2120     return stringtodouble(s1,d);
2121   }
2122 
inputline(const char * msg1,const char * msg2,string & s,bool numeric,int ypos,GIAC_CONTEXT)2123   int inputline(const char * msg1,const char * msg2,string & s,bool numeric,int ypos,GIAC_CONTEXT){
2124     //s=msg2;
2125     int pos=s.size(),beg=0;
2126     for (;;){
2127       int X1=print_msg12(msg1,msg2,ypos-30);
2128       int textX=X1,textY=ypos;
2129       drawRectangle(textX,textY,LCD_WIDTH_PX-textX-4,18,COLOR_WHITE);
2130       if (pos-beg>36)
2131 	beg=pos-12;
2132       if (int(s.size())-beg<36)
2133 	beg=giac::giacmax(0,int(s.size())-36);
2134       textX=X1;
2135 #if 0
2136       os_draw_string_(textX,textY,(s.substr(beg,pos-beg)+"|"+s.substr(pos,s.size()-pos)).c_str());
2137 #else
2138       textX=os_draw_string_(textX,textY+2,s.substr(beg,pos-beg).c_str());
2139       os_draw_string_(textX,textY+2,s.substr(pos,s.size()-pos).c_str());
2140       drawRectangle(textX,textY+4,2,13,COLOR_BLACK); // cursor
2141       // PrintMini(0,58,"         |        |        |        |  A<>a  |       ",4);
2142 #endif
2143       int key;
2144       GetKey(&key);
2145       if (key==KEY_SHUTDOWN)
2146 	return key;
2147       // if (!giac::freeze) set_xcas_status();
2148       if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK)
2149 	return KEY_CTRL_EXE;
2150       if (key>=32 && key<128){
2151 	if (!numeric || key=='-' || (key>='0' && key<='9')){
2152 	  s.insert(s.begin()+pos,char(key));
2153 	  ++pos;
2154 	}
2155 	continue;
2156       }
2157       if (key==KEY_CTRL_DEL){
2158 	if (pos){
2159 	  s.erase(s.begin()+pos-1);
2160 	  --pos;
2161 	}
2162 	continue;
2163       }
2164       if (key==KEY_CTRL_AC){
2165 	if (s=="")
2166 	  return KEY_CTRL_EXIT;
2167 	s="";
2168 	pos=0;
2169 	continue;
2170       }
2171       if (key==KEY_CTRL_EXIT)
2172 	return key;
2173       if (key==KEY_CTRL_RIGHT){
2174 	if (pos<s.size())
2175 	  ++pos;
2176 	continue;
2177       }
2178       if (key==KEY_SHIFT_RIGHT){
2179 	pos=s.size();
2180 	continue;
2181       }
2182       if (key==KEY_CTRL_LEFT){
2183 	if (pos)
2184 	  --pos;
2185 	continue;
2186       }
2187       if (key==KEY_SHIFT_LEFT){
2188 	pos=0;
2189 	continue;
2190       }
2191       if (const char * ans=keytostring(key,0,false,contextptr)){
2192 	insert(s,pos,ans);
2193 	pos+=strlen(ans);
2194 	continue;
2195       }
2196     }
2197   }
2198 
2199   logo_turtle * turtleptr=0;
2200 
turtle()2201   logo_turtle & turtle(){
2202     if (!turtleptr)
2203       turtleptr=new logo_turtle;
2204     return * turtleptr;
2205   }
2206 
2207 #ifdef NSPIRE_NEWLIB
2208   const int MAX_LOGO=2048;
2209 #else
2210   const int MAX_LOGO=368; // 512;
2211 #endif
2212 
turtle_stack()2213   std::vector<logo_turtle> & turtle_stack(){
2214     static std::vector<logo_turtle> * ans = 0;
2215     if (!ans){
2216       // initialize from python app storage
2217       ans=new std::vector<logo_turtle>(1,(*turtleptr));
2218 
2219     }
2220     return *ans;
2221   }
2222 
vecteur2turtle(const vecteur & v)2223   logo_turtle vecteur2turtle(const vecteur & v){
2224     int s=int(v.size());
2225     if (s>=5 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_ && v[2].type==_DOUBLE_ && v[3].type==_INT_ && v[4].type==_INT_ ){
2226       logo_turtle t;
2227       t.x=v[0]._DOUBLE_val;
2228       t.y=v[1]._DOUBLE_val;
2229       t.theta=v[2]._DOUBLE_val;
2230       int i=v[3].val;
2231       t.mark=(i%2)!=0;
2232       i=i >> 1;
2233       t.visible=(i%2)!=0;
2234       i=i >> 1;
2235       t.direct = (i%2)!=0;
2236       i=i >> 1;
2237       t.turtle_length = i & 0xff;
2238       i=i >> 8;
2239       t.color = i;
2240       t.radius = v[4].val;
2241       if (s>5 && v[5].type==_INT_)
2242 	t.s=v[5].val;
2243       else
2244 	t.s=-1;
2245       return t;
2246     }
2247 #ifndef NO_STDEXCEPT
2248     setsizeerr(gettext("vecteur2turtle")); // FIXME
2249 #endif
2250     return logo_turtle();
2251   }
2252 
turtle_status(const logo_turtle & turtle)2253   static int turtle_status(const logo_turtle & turtle){
2254     int status= (turtle.color << 11) | ( (turtle.turtle_length & 0xff) << 3) ;
2255     if (turtle.direct)
2256       status += 4;
2257     if (turtle.visible)
2258       status += 2;
2259     if (turtle.mark)
2260       status += 1;
2261     return status;
2262   }
2263 
set_turtle_state(const vecteur & v,GIAC_CONTEXT)2264   bool set_turtle_state(const vecteur & v,GIAC_CONTEXT){
2265     if (v.size()>=2 && v[0].type==_DOUBLE_ && v[1].type==_DOUBLE_){
2266       vecteur w(v);
2267       int s=int(w.size());
2268       if (s==2)
2269 	w.push_back(double((*turtleptr).theta));
2270       if (s<4)
2271 	w.push_back(turtle_status((*turtleptr)));
2272       if (s<5)
2273 	w.push_back(0);
2274       if (w[2].type==_DOUBLE_ && w[3].type==_INT_ && w[4].type==_INT_){
2275 	(*turtleptr)=vecteur2turtle(w);
2276 #ifdef TURTLETAB
2277 	turtle_stack_push_back(*turtleptr);
2278 #else
2279 	turtle_stack().push_back((*turtleptr));
2280 #endif
2281 	return true;
2282       }
2283     }
2284     return false;
2285   }
2286 
turtle2gen(const logo_turtle & turtle)2287   gen turtle2gen(const logo_turtle & turtle){
2288     return gen(makevecteur(turtle.x,turtle.y,double(turtle.theta),turtle_status(turtle),turtle.radius,turtle.s),_LOGO__VECT);
2289   }
2290 
turtle_state(GIAC_CONTEXT)2291   gen turtle_state(GIAC_CONTEXT){
2292     return turtle2gen((*turtleptr));
2293   }
2294 
update_turtle_state(bool clrstring,GIAC_CONTEXT)2295   static gen update_turtle_state(bool clrstring,GIAC_CONTEXT){
2296 #ifdef TURTLETAB
2297     if (turtle_stack_size>=MAX_LOGO)
2298       return gensizeerr("Not enough memory");
2299 #else
2300     if (turtle_stack().size()>=MAX_LOGO){
2301       ctrl_c=true; interrupted=true;
2302       return gensizeerr("Not enough memory");
2303     }
2304 #endif
2305     if (clrstring)
2306       (*turtleptr).s=-1;
2307     (*turtleptr).theta = (*turtleptr).theta - floor((*turtleptr).theta/360)*360;
2308 #ifdef TURTLETAB
2309     turtle_stack_push_back((*turtleptr));
2310 #else
2311     turtle_stack().push_back((*turtleptr));
2312 #endif
2313     gen res=turtle_state(contextptr);
2314 #ifdef EMCC // should directly interact with canvas
2315     return gen(turtlevect2vecteur(turtle_stack()),_LOGO__VECT);
2316 #endif
2317     return res;
2318   }
2319 
2320   int turtle_speed=0;
_speed(const gen & g,GIAC_CONTEXT)2321   gen _speed(const gen & g,GIAC_CONTEXT){
2322     if ( g.type==_STRNG && g.subtype==-1) return  g;
2323     if (g.type==_VECT && g._VECTptr->empty())
2324       return turtle_speed;
2325     if (g.type!=_INT_)
2326       return gensizeerr(contextptr);
2327     int i=g.val;
2328     if (i<0) i=0;
2329     if (i>1000) i=1000;
2330     turtle_speed=i;
2331     return i;
2332   }
2333   static const char _speed_s []="speed";
2334   static define_unary_function_eval2 (__speed,&_speed,_speed_s,&printastifunction);
2335   define_unary_function_ptr5( at_speed ,alias_at_speed,&__speed,0,T_LOGO);
2336 
_avance(const gen & g,GIAC_CONTEXT)2337   gen _avance(const gen & g,GIAC_CONTEXT){
2338     if ( g.type==_STRNG && g.subtype==-1) return  g;
2339     // logo instruction
2340     double i;
2341     if (g.type!=_INT_){
2342       if (g.type==_VECT)
2343 	i=(*turtleptr).turtle_length;
2344       else {
2345 	gen g1=evalf_double(g,1,contextptr);
2346 	if (g1.type==_DOUBLE_)
2347 	  i=g1._DOUBLE_val;
2348 	else
2349 	  return gensizeerr(contextptr);
2350       }
2351     }
2352     else
2353       i=g.val;
2354     (*turtleptr).x += i * std::cos((*turtleptr).theta*deg2rad_d);
2355     (*turtleptr).y += i * std::sin((*turtleptr).theta*deg2rad_d) ;
2356     (*turtleptr).radius = 0;
2357     return update_turtle_state(true,contextptr);
2358   }
2359   static const char _avance_s []="avance";
2360   static define_unary_function_eval2 (__avance,&_avance,_avance_s,&printastifunction);
2361   define_unary_function_ptr5( at_avance ,alias_at_avance,&__avance,0,T_LOGO);
2362 
2363   static const char _forward_s []="forward";
2364   static define_unary_function_eval (__forward,&_avance,_forward_s);
2365   define_unary_function_ptr5( at_forward ,alias_at_forward,&__forward,0,true);
2366 
_recule(const gen & g,GIAC_CONTEXT)2367   gen _recule(const gen & g,GIAC_CONTEXT){
2368     if ( g.type==_STRNG && g.subtype==-1) return  g;
2369     // logo instruction
2370     if (g.type==_VECT)
2371       return _avance(-(*turtleptr).turtle_length,contextptr);
2372     return _avance(-g,contextptr);
2373   }
2374   static const char _recule_s []="recule";
2375   static define_unary_function_eval2 (__recule,&_recule,_recule_s,&printastifunction);
2376   define_unary_function_ptr5( at_recule ,alias_at_recule,&__recule,0,T_LOGO);
2377 
2378   static const char _backward_s []="backward";
2379   static define_unary_function_eval (__backward,&_recule,_backward_s);
2380   define_unary_function_ptr5( at_backward ,alias_at_backward,&__backward,0,true);
2381 
_position(const gen & g,GIAC_CONTEXT)2382   gen _position(const gen & g,GIAC_CONTEXT){
2383     if ( g.type==_STRNG && g.subtype==-1) return  g;
2384     // logo instruction
2385     if (g.type!=_VECT)
2386       return makevecteur((*turtleptr).x,(*turtleptr).y);
2387     // return turtle_state();
2388     vecteur v = *g._VECTptr;
2389     int s=int(v.size());
2390     if (!s)
2391       return makevecteur((*turtleptr).x,(*turtleptr).y);
2392     v[0]=evalf_double(v[0],1,contextptr);
2393     if (s>1)
2394       v[1]=evalf_double(v[1],1,contextptr);
2395     if (s>2)
2396       v[2]=evalf_double(v[2],1,contextptr);
2397     if (set_turtle_state(v,contextptr))
2398       return update_turtle_state(true,contextptr);
2399     return zero;
2400   }
2401   static const char _position_s []="position";
2402   static define_unary_function_eval2 (__position,&_position,_position_s,&printastifunction);
2403   define_unary_function_ptr5( at_position ,alias_at_position,&__position,0,T_LOGO);
2404 
_cap(const gen & g,GIAC_CONTEXT)2405   gen _cap(const gen & g,GIAC_CONTEXT){
2406     if ( g.type==_STRNG && g.subtype==-1) return  g;
2407     // logo instruction
2408     gen gg=evalf_double(g,1,contextptr);
2409     if (gg.type!=_DOUBLE_)
2410       return double((*turtleptr).theta);
2411     (*turtleptr).theta=gg._DOUBLE_val;
2412     (*turtleptr).radius = 0;
2413     return update_turtle_state(true,contextptr);
2414   }
2415   static const char _cap_s []="cap";
2416   static define_unary_function_eval2 (__cap,&_cap,_cap_s,&printastifunction);
2417   define_unary_function_ptr5( at_cap ,alias_at_cap,&__cap,0,T_LOGO);
2418 
2419   static const char _heading_s []="heading";
2420   static define_unary_function_eval (__heading,&_cap,_heading_s);
2421   define_unary_function_ptr5( at_heading ,alias_at_heading,&__heading,0,true);
2422 
2423 
_tourne_droite(const gen & g,GIAC_CONTEXT)2424   gen _tourne_droite(const gen & g,GIAC_CONTEXT){
2425     if ( g.type==_STRNG && g.subtype==-1) return  g;
2426     // logo instruction
2427     if (g.type!=_INT_){
2428       if (g.type==_VECT)
2429 	(*turtleptr).theta -= 90;
2430       else {
2431 	gen g1=evalf_double(g,1,contextptr);
2432 	if (g1.type==_DOUBLE_)
2433 	  (*turtleptr).theta -= g1._DOUBLE_val;
2434 	else
2435 	  return gensizeerr(contextptr);
2436       }
2437     }
2438     else
2439       (*turtleptr).theta -= g.val;
2440     (*turtleptr).radius = 0;
2441     return update_turtle_state(true,contextptr);
2442   }
2443   static const char _tourne_droite_s []="tourne_droite";
2444   static define_unary_function_eval2 (__tourne_droite,&_tourne_droite,_tourne_droite_s,&printastifunction);
2445   define_unary_function_ptr5( at_tourne_droite ,alias_at_tourne_droite,&__tourne_droite,0,T_LOGO);
2446 
_tourne_gauche(const gen & g,GIAC_CONTEXT)2447   gen _tourne_gauche(const gen & g,GIAC_CONTEXT){
2448     if ( g.type==_STRNG && g.subtype==-1) return  g;
2449     // logo instruction
2450     if (g.type==_VECT){
2451       (*turtleptr).theta += 90;
2452       (*turtleptr).radius = 0;
2453       return update_turtle_state(true,contextptr);
2454     }
2455     return _tourne_droite(-g,contextptr);
2456   }
2457   static const char _tourne_gauche_s []="tourne_gauche";
2458   static define_unary_function_eval2 (__tourne_gauche,&_tourne_gauche,_tourne_gauche_s,&printastifunction);
2459   define_unary_function_ptr5( at_tourne_gauche ,alias_at_tourne_gauche,&__tourne_gauche,0,T_LOGO);
2460 
_leve_crayon(const gen & g,GIAC_CONTEXT)2461   gen _leve_crayon(const gen & g,GIAC_CONTEXT){
2462     if ( g.type==_STRNG && g.subtype==-1) return  g;
2463     // logo instruction
2464     (*turtleptr).mark = false;
2465     (*turtleptr).radius = 0;
2466     return update_turtle_state(true,contextptr);
2467   }
2468   static const char _leve_crayon_s []="leve_crayon";
2469   static define_unary_function_eval2 (__leve_crayon,&_leve_crayon,_leve_crayon_s,&printastifunction);
2470   define_unary_function_ptr5( at_leve_crayon ,alias_at_leve_crayon,&__leve_crayon,0,T_LOGO);
2471 
2472   static const char _penup_s []="penup";
2473   static define_unary_function_eval (__penup,&_leve_crayon,_penup_s);
2474   define_unary_function_ptr5( at_penup ,alias_at_penup,&__penup,0,T_LOGO);
2475 
_baisse_crayon(const gen & g,GIAC_CONTEXT)2476   gen _baisse_crayon(const gen & g,GIAC_CONTEXT){
2477     if ( g.type==_STRNG && g.subtype==-1) return  g;
2478     // logo instruction
2479     (*turtleptr).mark = true;
2480     (*turtleptr).radius = 0;
2481     return update_turtle_state(true,contextptr);
2482   }
2483   static const char _baisse_crayon_s []="baisse_crayon";
2484   static define_unary_function_eval2 (__baisse_crayon,&_baisse_crayon,_baisse_crayon_s,&printastifunction);
2485   define_unary_function_ptr5( at_baisse_crayon ,alias_at_baisse_crayon,&__baisse_crayon,0,T_LOGO);
2486 
2487   static const char _pendown_s []="pendown";
2488   static define_unary_function_eval (__pendown,&_baisse_crayon,_pendown_s);
2489   define_unary_function_ptr5( at_pendown ,alias_at_pendown,&__pendown,0,T_LOGO);
2490 
2491   vector<string> * ecrisptr=0;
ecristab()2492   vector<string> & ecristab(){
2493     if (!ecrisptr)
2494       ecrisptr=new vector<string>;
2495     return * ecrisptr;
2496   }
_ecris(const gen & g,GIAC_CONTEXT)2497   gen _ecris(const gen & g,GIAC_CONTEXT){
2498     if ( g.type==_STRNG && g.subtype==-1) return  g;
2499 #if 0 //def TURTLETAB
2500     return gensizeerr("String support does not work with static turtle table");
2501 #endif
2502     // logo instruction
2503     (*turtleptr).radius=14;
2504     if (g.type==_VECT){
2505       vecteur & v =*g._VECTptr;
2506       int s=int(v.size());
2507       if (s==2 && v[1].type==_INT_){
2508 	(*turtleptr).radius=absint(v[1].val);
2509 	(*turtleptr).s=ecristab().size();
2510 	ecristab().push_back(gen2string(v.front()));
2511 	return update_turtle_state(false,contextptr);
2512       }
2513       if (s==4 && v[1].type==_INT_ && v[2].type==_INT_ && v[3].type==_INT_){
2514 	logo_turtle t=(*turtleptr);
2515 	_leve_crayon(0,contextptr);
2516 	_position(makevecteur(v[2],v[3]),contextptr);
2517 	(*turtleptr).radius=absint(v[1].val);
2518 	(*turtleptr).s=ecristab().size();
2519 	ecristab().push_back(gen2string(v.front()));
2520 	update_turtle_state(false,contextptr);
2521 	(*turtleptr)=t;
2522 	return update_turtle_state(true,contextptr);
2523       }
2524     }
2525     (*turtleptr).s=ecristab().size();
2526     ecristab().push_back(gen2string(g));
2527     return update_turtle_state(false,contextptr);
2528   }
2529   static const char _ecris_s []="ecris";
2530   static define_unary_function_eval2 (__ecris,&_ecris,_ecris_s,&printastifunction);
2531   define_unary_function_ptr5( at_ecris ,alias_at_ecris,&__ecris,0,T_LOGO);
2532 
_signe(const gen & g,GIAC_CONTEXT)2533   gen _signe(const gen & g,GIAC_CONTEXT){
2534     if ( g.type==_STRNG && g.subtype==-1) return  g;
2535     // logo instruction
2536     return _ecris(makevecteur(g,20,10,10),contextptr);
2537   }
2538   static const char _signe_s []="signe";
2539   static define_unary_function_eval2 (__signe,&_signe,_signe_s,&printastifunction);
2540   define_unary_function_ptr5( at_signe ,alias_at_signe,&__signe,0,T_LOGO);
2541 
_saute(const gen & g,GIAC_CONTEXT)2542   gen _saute(const gen & g,GIAC_CONTEXT){
2543     if ( g.type==_STRNG && g.subtype==-1) return  g;
2544     _leve_crayon(0,contextptr);
2545     _avance(g,contextptr);
2546     return _baisse_crayon(0,contextptr);
2547   }
2548   static const char _saute_s []="saute";
2549   static define_unary_function_eval2 (__saute,&_saute,_saute_s,&printastifunction);
2550   define_unary_function_ptr5( at_saute ,alias_at_saute,&__saute,0,T_LOGO);
2551 
2552   static const char _jump_s []="jump";
2553   static define_unary_function_eval2 (__jump,&_saute,_jump_s,&printastifunction);
2554   define_unary_function_ptr5( at_jump ,alias_at_jump,&__jump,0,T_LOGO);
2555 
_pas_de_cote(const gen & g,GIAC_CONTEXT)2556   gen _pas_de_cote(const gen & g,GIAC_CONTEXT){
2557     if ( g.type==_STRNG && g.subtype==-1) return  g;
2558     _leve_crayon(0,contextptr);
2559     _tourne_droite(-90,contextptr);
2560     _avance(g,contextptr);
2561     _tourne_droite(90,contextptr);
2562     return _baisse_crayon(0,contextptr);
2563   }
2564   static const char _pas_de_cote_s []="pas_de_cote";
2565   static define_unary_function_eval2 (__pas_de_cote,&_pas_de_cote,_pas_de_cote_s,&printastifunction);
2566   define_unary_function_ptr5( at_pas_de_cote ,alias_at_pas_de_cote,&__pas_de_cote,0,T_LOGO);
2567 
2568   static const char _skip_s []="skip";
2569   static define_unary_function_eval2 (__skip,&_pas_de_cote,_skip_s,&printastifunction);
2570   define_unary_function_ptr5( at_skip ,alias_at_skip,&__skip,0,T_LOGO);
2571 
_cache_tortue(const gen & g,GIAC_CONTEXT)2572   gen _cache_tortue(const gen & g,GIAC_CONTEXT){
2573     if ( g.type==_STRNG && g.subtype==-1) return  g;
2574     // logo instruction
2575     (*turtleptr).visible=false;
2576     (*turtleptr).radius = 0;
2577     return update_turtle_state(true,contextptr);
2578   }
2579   static const char _cache_tortue_s []="cache_tortue";
2580   static define_unary_function_eval2 (__cache_tortue,&_cache_tortue,_cache_tortue_s,&printastifunction);
2581   define_unary_function_ptr5( at_cache_tortue ,alias_at_cache_tortue,&__cache_tortue,0,T_LOGO);
2582 
2583   static const char _hideturtle_s []="hideturtle";
2584   static define_unary_function_eval (__hideturtle,&_cache_tortue,_hideturtle_s);
2585   define_unary_function_ptr5( at_hideturtle ,alias_at_hideturtle,&__hideturtle,0,true);
2586 
_montre_tortue(const gen & g,GIAC_CONTEXT)2587   gen _montre_tortue(const gen & g,GIAC_CONTEXT){
2588     if ( g.type==_STRNG && g.subtype==-1) return  g;
2589     // logo instruction
2590     (*turtleptr).visible=true;
2591     (*turtleptr).radius = 0;
2592     return update_turtle_state(true,contextptr);
2593   }
2594   static const char _montre_tortue_s []="montre_tortue";
2595   static define_unary_function_eval2 (__montre_tortue,&_montre_tortue,_montre_tortue_s,&printastifunction);
2596   define_unary_function_ptr5( at_montre_tortue ,alias_at_montre_tortue,&__montre_tortue,0,T_LOGO);
2597 
2598   static const char _showturtle_s []="showturtle";
2599   static define_unary_function_eval (__showturtle,&_montre_tortue,_showturtle_s);
2600   define_unary_function_ptr5( at_showturtle ,alias_at_showturtle,&__showturtle,0,true);
2601 
2602 
_repete(const gen & g,GIAC_CONTEXT)2603   gen _repete(const gen & g,GIAC_CONTEXT){
2604     if ( g.type==_STRNG && g.subtype==-1) return  g;
2605     if (g.type!=_VECT || g._VECTptr->size()<2)
2606       return gensizeerr(contextptr);
2607     // logo instruction
2608     vecteur v = *g._VECTptr;
2609     v[0]=eval(v[0],contextptr);
2610     if (v.front().type!=_INT_)
2611       return gentypeerr(contextptr);
2612     gen prog=vecteur(v.begin()+1,v.end());
2613     int i=absint(v.front().val);
2614     gen res;
2615     for (int j=0;j<i;++j){
2616       res=eval(prog,contextptr);
2617     }
2618     return res;
2619   }
2620   static const char _repete_s []="repete";
2621   static define_unary_function_eval_quoted (__repete,&_repete,_repete_s);
2622   define_unary_function_ptr5( at_repete ,alias_at_repete,&__repete,_QUOTE_ARGUMENTS,T_RETURN);
2623 
_crayon(const gen & g,GIAC_CONTEXT)2624   gen _crayon(const gen & g,GIAC_CONTEXT){
2625     if ( g.type==_STRNG && g.subtype==-1) return  g;
2626     if (g.type==_STRNG) return _crayon(gen(*g._STRNGptr,contextptr),contextptr);
2627     // logo instruction
2628     if (g.type==_VECT && g._VECTptr->size()==3)
2629       return _crayon(_rgb(g,contextptr),contextptr);
2630     if (g.type!=_INT_){
2631       gen res=(*turtleptr).color;
2632       res.subtype=_INT_COLOR;
2633       return res;
2634     }
2635     (*turtleptr).color=g.val;
2636     (*turtleptr).radius = 0;
2637     return update_turtle_state(true,contextptr);
2638   }
2639   static const char _crayon_s []="crayon";
2640   static define_unary_function_eval2 (__crayon,&_crayon,_crayon_s,&printastifunction);
2641   define_unary_function_ptr5( at_crayon ,alias_at_crayon,&__crayon,0,T_LOGO);
2642 
2643   static const char _pencolor_s []="pencolor";
2644   static define_unary_function_eval (__pencolor,&_crayon,_pencolor_s);
2645   define_unary_function_ptr5( at_pencolor ,alias_at_pencolor,&__pencolor,0,T_LOGO);
2646 
_efface_logo(const gen & g,GIAC_CONTEXT)2647   gen _efface_logo(const gen & g,GIAC_CONTEXT){
2648     if ( g.type==_STRNG && g.subtype==-1) return  g;
2649     if (g.type==_INT_){
2650       _crayon(int(FL_WHITE),contextptr);
2651       _recule(g,contextptr);
2652       return _crayon(0,contextptr);
2653     }
2654     // logo instruction
2655     (*turtleptr) = logo_turtle();
2656 #ifdef TURTLETAB
2657     turtle_stack_size=0;
2658 #else
2659     turtle_stack().clear();
2660 #endif
2661     ecristab().clear();
2662     if (g.type==_VECT && g._VECTptr->size()==2){
2663       vecteur v = *g._VECTptr;
2664       int s=int(v.size());
2665       v[0]=evalf_double(v[0],1,contextptr);
2666       if (s>1)
2667 	v[1]=evalf_double(v[1],1,contextptr);
2668       (*turtleptr).mark = false; // leve_crayon
2669       (*turtleptr).radius = 0;
2670       update_turtle_state(true,contextptr);
2671       set_turtle_state(v,contextptr); // baisse_crayon
2672       update_turtle_state(true,contextptr);
2673       (*turtleptr).mark = true;
2674       (*turtleptr).radius = 0;
2675     }
2676     return update_turtle_state(true,contextptr);
2677   }
2678   static const char _efface_logo_s []="efface";
2679   static define_unary_function_eval2 (__efface_logo,&_efface_logo,_efface_logo_s,&printastifunction);
2680   define_unary_function_ptr5( at_efface_logo ,alias_at_efface_logo,&__efface_logo,0,T_LOGO);
2681 
2682   static const char _efface_s []="efface";
2683   static define_unary_function_eval2 (__efface,&_efface_logo,_efface_s,&printastifunction);
2684   define_unary_function_ptr5( at_efface ,alias_at_efface,&__efface,0,T_LOGO);
2685 
2686   static const char _reset_s []="reset";
2687   static define_unary_function_eval2 (__reset,&_efface_logo,_reset_s,&printastifunction);
2688   define_unary_function_ptr5( at_reset ,alias_at_reset,&__reset,0,T_LOGO);
2689 
2690   static const char _clearscreen_s []="clearscreen";
2691   static define_unary_function_eval2 (__clearscreen,&_efface_logo,_clearscreen_s,&printastifunction);
2692   define_unary_function_ptr5( at_clearscreen ,alias_at_clearscreen,&__clearscreen,0,T_LOGO);
2693 
_debut_enregistrement(const gen & g,GIAC_CONTEXT)2694   gen _debut_enregistrement(const gen &g,GIAC_CONTEXT){
2695     return undef;
2696   }
2697   static const char _debut_enregistrement_s []="debut_enregistrement";
2698   static define_unary_function_eval2 (__debut_enregistrement,&_debut_enregistrement,_debut_enregistrement_s,&printastifunction);
2699   define_unary_function_ptr5( at_debut_enregistrement ,alias_at_debut_enregistrement,&__debut_enregistrement,0,T_LOGO);
2700 
2701   static const char _fin_enregistrement_s []="fin_enregistrement";
2702   static define_unary_function_eval2 (__fin_enregistrement,&_debut_enregistrement,_fin_enregistrement_s,&printastifunction);
2703   define_unary_function_ptr5( at_fin_enregistrement ,alias_at_fin_enregistrement,&__fin_enregistrement,0,T_LOGO);
2704 
2705   static const char _turtle_stack_s []="turtle_stack";
2706   static define_unary_function_eval2 (__turtle_stack,&_debut_enregistrement,_turtle_stack_s,&printastifunction);
2707   define_unary_function_ptr5( at_turtle_stack ,alias_at_turtle_stack,&__turtle_stack,0,T_LOGO);
2708 
_vers(const gen & g,GIAC_CONTEXT)2709   gen _vers(const gen & g,GIAC_CONTEXT){
2710     if ( g.type==_STRNG && g.subtype==-1) return  g;
2711     // logo instruction
2712     if (g.type!=_VECT || g._VECTptr->size()!=2)
2713       return gensizeerr(contextptr);
2714     gen x=evalf_double(g._VECTptr->front(),1,contextptr),
2715       y=evalf_double(g._VECTptr->back(),1,contextptr);
2716     if (x.type!=_DOUBLE_ || y.type!=_DOUBLE_)
2717       return gensizeerr(contextptr);
2718     double xv=x._DOUBLE_val,yv=y._DOUBLE_val,xt=(*turtleptr).x,yt=(*turtleptr).y;
2719     double theta=atan2(yv-yt,xv-xt);
2720     return _cap(theta*180/M_PI,contextptr);
2721   }
2722   static const char _vers_s []="vers";
2723   static define_unary_function_eval2 (__vers,&_vers,_vers_s,&printastifunction);
2724   define_unary_function_ptr5( at_vers ,alias_at_vers,&__vers,0,T_LOGO);
2725 
find_radius(const gen & g,int & r,int & theta2,bool & direct)2726   static int find_radius(const gen & g,int & r,int & theta2,bool & direct){
2727     int radius;
2728     direct=true;
2729     theta2 = 360 ;
2730     // logo instruction
2731     if (g.type==_VECT && !g._VECTptr->empty()){
2732       vecteur v = *g._VECTptr;
2733       bool seg=false;
2734       if (v.back()==at_segment){
2735 	v.pop_back();
2736 	seg=true;
2737       }
2738       if (v.size()<2)
2739 	return RAND_MAX; // setdimerr(contextptr);
2740       if (v[0].type==_INT_)
2741 	r=v[0].val;
2742       else {
2743 	gen v0=evalf_double(v[0],1,context0);
2744 	if (v0.type==_DOUBLE_)
2745 	  r=int(v0._DOUBLE_val+0.5);
2746 	else
2747 	  return RAND_MAX; // setsizeerr(contextptr);
2748       }
2749       if (r<0){
2750 	r=-r;
2751 	direct=false;
2752       }
2753       int theta1;
2754       if (v[1].type==_DOUBLE_)
2755 	theta1=int(v[1]._DOUBLE_val+0.5);
2756       else {
2757 	if (v[1].type==_INT_)
2758 	  theta1=v[1].val;
2759 	else return RAND_MAX; // setsizeerr(contextptr);
2760       }
2761       while (theta1<0)
2762 	theta1 += 360;
2763       if (v.size()>=3){
2764 	if (v[2].type==_DOUBLE_)
2765 	  theta2 = int(v[2]._DOUBLE_val+0.5);
2766 	else {
2767 	  if (v[2].type==_INT_)
2768 	    theta2 = v[2].val;
2769 	  else return RAND_MAX; // setsizeerr(contextptr);
2770 	}
2771 	while (theta2<0)
2772 	  theta2 += 360;
2773 	radius = giacmin(r,512) | (giacmin(theta1,360) << 9) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0);
2774       }
2775       else {// angle 1=0
2776 	theta2 = theta1;
2777 	if (theta2<0)
2778 	  theta2 += 360;
2779 	radius = giacmin(r,512) | (giacmin(theta2,360) << 18 ) | (seg?(1<<28):0);
2780       }
2781       return radius;
2782     }
2783     radius = 10;
2784     if (g.type==_INT_)
2785       radius= (r=g.val);
2786     if (g.type==_DOUBLE_)
2787       radius= (r=int(g._DOUBLE_val));
2788     if (radius<=0){
2789       radius = -radius;
2790       direct=false;
2791     }
2792     radius = giacmin(radius,512 )+(360 << 18) ; // 2nd angle = 360 degrees
2793     return radius;
2794   }
2795 
turtle_move(int r,int theta2,GIAC_CONTEXT)2796   static void turtle_move(int r,int theta2,GIAC_CONTEXT){
2797     double theta0;
2798     if ((*turtleptr).direct)
2799       theta0=(*turtleptr).theta-90;
2800     else {
2801       theta0=(*turtleptr).theta+90;
2802       theta2=-theta2;
2803     }
2804     (*turtleptr).x += r*(std::cos(M_PI/180*(theta2+theta0))-std::cos(M_PI/180*theta0));
2805     (*turtleptr).y += r*(std::sin(M_PI/180*(theta2+theta0))-std::sin(M_PI/180*theta0));
2806     (*turtleptr).theta = (*turtleptr).theta+theta2 ;
2807     if ((*turtleptr).theta<0)
2808       (*turtleptr).theta += 360;
2809     if ((*turtleptr).theta>360)
2810       (*turtleptr).theta -= 360;
2811   }
2812 
_rond(const gen & g,GIAC_CONTEXT)2813   gen _rond(const gen & g,GIAC_CONTEXT){
2814     if ( g.type==_STRNG && g.subtype==-1) return  g;
2815     int r,theta2,tmpr;
2816     tmpr=find_radius(g,r,theta2,(*turtleptr).direct);
2817     if (tmpr==RAND_MAX)
2818       return gensizeerr(contextptr);
2819     (*turtleptr).radius=tmpr;
2820     turtle_move(r,theta2,contextptr);
2821     return update_turtle_state(true,contextptr);
2822   }
2823   static const char _rond_s []="rond";
2824   static define_unary_function_eval2 (__rond,&_rond,_rond_s,&printastifunction);
2825   define_unary_function_ptr5( at_rond ,alias_at_rond,&__rond,0,T_LOGO);
2826 
_disque(const gen & g,GIAC_CONTEXT)2827   gen _disque(const gen & g,GIAC_CONTEXT){
2828     if ( g.type==_STRNG && g.subtype==-1) return  g;
2829     int r,theta2,tmpr=find_radius(g,r,theta2,(*turtleptr).direct);
2830     if (tmpr==RAND_MAX)
2831       return gensizeerr(contextptr);
2832     (*turtleptr).radius=tmpr;
2833     turtle_move(r,theta2,contextptr);
2834     (*turtleptr).radius += 1 << 27;
2835     return update_turtle_state(true,contextptr);
2836   }
2837   static const char _disque_s []="disque";
2838   static define_unary_function_eval2 (__disque,&_disque,_disque_s,&printastifunction);
2839   define_unary_function_ptr5( at_disque ,alias_at_disque,&__disque,0,T_LOGO);
2840 
_disque_centre(const gen & g,GIAC_CONTEXT)2841   gen _disque_centre(const gen & g,GIAC_CONTEXT){
2842     if ( g.type==_STRNG && g.subtype==-1) return  g;
2843     int r,theta2;
2844     bool direct;
2845     int radius=find_radius(g,r,theta2,direct);
2846     if (radius==RAND_MAX)
2847       return gensizeerr(contextptr);
2848     r=absint(r);
2849     _saute(r,contextptr);
2850     _tourne_gauche(direct?90:-90,contextptr);
2851     (*turtleptr).radius = radius;
2852     (*turtleptr).direct=direct;
2853     turtle_move(r,theta2,contextptr);
2854     (*turtleptr).radius += 1 << 27;
2855     update_turtle_state(true,contextptr);
2856     _tourne_droite(direct?90:-90,contextptr);
2857     return _saute(-r,contextptr);
2858   }
2859   static const char _disque_centre_s []="disque_centre";
2860   static define_unary_function_eval2 (__disque_centre,&_disque_centre,_disque_centre_s,&printastifunction);
2861   define_unary_function_ptr5( at_disque_centre ,alias_at_disque_centre,&__disque_centre,0,T_LOGO);
2862 
_polygone_rempli(const gen & g,GIAC_CONTEXT)2863   gen _polygone_rempli(const gen & g,GIAC_CONTEXT){
2864     if ( g.type==_STRNG && g.subtype==-1) return  g;
2865     if (g.type==_INT_){
2866       (*turtleptr).radius=-absint(g.val);
2867       if ((*turtleptr).radius<-1)
2868 	return update_turtle_state(true,contextptr);
2869     }
2870     return gensizeerr(gettext("Integer argument >= 2"));
2871   }
2872   static const char _polygone_rempli_s []="polygone_rempli";
2873   static define_unary_function_eval2 (__polygone_rempli,&_polygone_rempli,_polygone_rempli_s,&printastifunction);
2874   define_unary_function_ptr5( at_polygone_rempli ,alias_at_polygone_rempli,&__polygone_rempli,0,T_LOGO);
2875 
_rectangle_plein(const gen & g,GIAC_CONTEXT)2876   gen _rectangle_plein(const gen & g,GIAC_CONTEXT){
2877     if ( g.type==_STRNG && g.subtype==-1) return  g;
2878     gen gx=g,gy=g;
2879     if (g.type==_VECT && g._VECTptr->size()==2){
2880       gx=g._VECTptr->front();
2881       gy=g._VECTptr->back();
2882     }
2883     for (int i=0;i<2;++i){
2884       _avance(gx,contextptr);
2885       _tourne_droite(-90,contextptr);
2886       _avance(gy,contextptr);
2887       _tourne_droite(-90,contextptr);
2888     }
2889     //for (int i=0;i<turtle_stack().size();++i){ *logptr(contextptr) << turtle2gen(turtle_stack()[i]) <<endl;}
2890     return _polygone_rempli(-8,contextptr);
2891   }
2892   static const char _rectangle_plein_s []="rectangle_plein";
2893   static define_unary_function_eval2 (__rectangle_plein,&_rectangle_plein,_rectangle_plein_s,&printastifunction);
2894   define_unary_function_ptr5( at_rectangle_plein ,alias_at_rectangle_plein,&__rectangle_plein,0,T_LOGO);
2895 
_triangle_plein(const gen & g,GIAC_CONTEXT)2896   gen _triangle_plein(const gen & g,GIAC_CONTEXT){
2897     if ( g.type==_STRNG && g.subtype==-1) return  g;
2898     gen gx=g,gy=g,gtheta=60;
2899     if (g.type==_VECT && g._VECTptr->size()>=2){
2900       vecteur & v=*g._VECTptr;
2901       gx=v.front();
2902       gy=v[1];
2903       gtheta=90;
2904       if (v.size()>2)
2905 	gtheta=v[2];
2906     }
2907     logo_turtle t=(*turtleptr);
2908     _avance(gx,contextptr);
2909     double save_x=(*turtleptr).x,save_y=(*turtleptr).y;
2910     _recule(gx,contextptr);
2911     _tourne_gauche(gtheta,contextptr);
2912     _avance(gy,contextptr);
2913     (*turtleptr).x=save_x;
2914     (*turtleptr).y=save_y;
2915     update_turtle_state(true,contextptr);
2916     (*turtleptr)=t;
2917     (*turtleptr).radius=0;
2918     update_turtle_state(true,contextptr);
2919     return _polygone_rempli(-3,contextptr);
2920   }
2921   static const char _triangle_plein_s []="triangle_plein";
2922   static define_unary_function_eval2 (__triangle_plein,&_triangle_plein,_triangle_plein_s,&printastifunction);
2923   define_unary_function_ptr5( at_triangle_plein ,alias_at_triangle_plein,&__triangle_plein,0,T_LOGO);
2924 
_dessine_tortue(const gen & g,GIAC_CONTEXT)2925   gen _dessine_tortue(const gen & g,GIAC_CONTEXT){
2926     if ( g.type==_STRNG && g.subtype==-1) return  g;
2927     // logo instruction
2928     /*
2929       _triangle_plein(makevecteur(17,5));
2930       _tourne_droite(90);
2931       _triangle_plein(makevecteur(5,17));
2932       return _tourne_droite(-90);
2933     */
2934     double save_x=(*turtleptr).x,save_y=(*turtleptr).y;
2935     _tourne_droite(90,contextptr);
2936     _avance(5,contextptr);
2937     _tourne_gauche(106,contextptr);
2938     _avance(18,contextptr);
2939     _tourne_gauche(148,contextptr);
2940     _avance(18,contextptr);
2941     _tourne_gauche(106,contextptr);
2942     _avance(5,contextptr);
2943     (*turtleptr).x=save_x; (*turtleptr).y=save_y;
2944     gen res(_tourne_gauche(90,contextptr));
2945     if (is_one(g))
2946       return res;
2947     return _polygone_rempli(-9,contextptr);
2948   }
2949   static const char _dessine_tortue_s []="dessine_tortue";
2950   static define_unary_function_eval2 (__dessine_tortue,&_dessine_tortue,_dessine_tortue_s,&printastifunction);
2951   define_unary_function_ptr5( at_dessine_tortue ,alias_at_dessine_tortue,&__dessine_tortue,0,T_LOGO);
2952 
2953 #ifndef NO_NAMESPACE_GIAC
2954 } // namespace giac
2955 #endif // ndef NO_NAMESPACE_GIAC
2956 
2957 
2958 #ifndef NO_NAMESPACE_XCAS
2959 namespace xcas {
2960 #endif // ndef NO_NAMESPACE_XCAS
drawRectangle(int x,int y,int w,int h,int c)2961   void drawRectangle(int x,int y,int w,int h,int c){
2962     draw_rectangle(x,y,w,h,c,context0);
2963   }
draw_rectangle(int x,int y,int w,int h,int c)2964   void draw_rectangle(int x,int y,int w,int h,int c){
2965     draw_rectangle(x,y,w,h,c,context0);
2966   }
draw_line(int x0,int y0,int x1,int y1,int c)2967   void draw_line(int x0,int y0,int x1,int y1,int c){
2968     draw_line(x0,y0,x1,y1,c,context0);
2969   }
draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4)2970   void draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4){
2971     draw_circle(xc,yc,r,color,q1,q2,q3,q4,context0);
2972   }
draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right)2973   void draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right){
2974     draw_filled_circle(xc,yc,r,color,left,right,context0);
2975   }
draw_polygon(std::vector<std::vector<int>> & v1,int color)2976   void draw_polygon(std::vector< std::vector<int> > & v1,int color){
2977     draw_polygon(v1,color,context0);
2978   }
draw_filled_polygon(std::vector<vector<int>> & L,int xmin,int xmax,int ymin,int ymax,int color)2979   void draw_filled_polygon(std::vector< vector<int> > &L,int xmin,int xmax,int ymin,int ymax,int color){
2980     draw_filled_polygon(L,xmin,xmax,ymin,ymax,color,context0);
2981   }
draw_arc(int xc,int yc,int rx,int ry,int color,double theta1,double theta2)2982   void draw_arc(int xc,int yc,int rx,int ry,int color,double theta1, double theta2){
2983     draw_arc(xc,yc,rx,ry,color,theta1,theta2,giac::context0);
2984   }
draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment)2985   void draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment){
2986     draw_filled_arc(x,y,rx,ry,theta1_deg,theta2_deg,color,xmin,xmax,ymin,ymax,segment,context0);
2987   }
2988 
2989 
2990   unsigned max_prettyprint_equation=256;
2991 
2992   // make a free copy of g
Equation_copy(const gen & g)2993   gen Equation_copy(const gen & g){
2994     if (g.type==_EQW)
2995       return *g._EQWptr;
2996     if (g.type!=_VECT)
2997       return g;
2998     vecteur & v = *g._VECTptr;
2999     const_iterateur it=v.begin(),itend=v.end();
3000     vecteur res;
3001     res.reserve(itend-it);
3002     for (;it!=itend;++it)
3003       res.push_back(Equation_copy(*it));
3004     return gen(res,g.subtype);
3005   }
3006 
3007   // matrix/list select
do_select(gen & eql,bool select,gen & value)3008   bool do_select(gen & eql,bool select,gen & value){
3009     if (eql.type==_VECT && !eql._VECTptr->empty()){
3010       vecteur & v=*eql._VECTptr;
3011       size_t s=v.size();
3012       if (v[s-1].type!=_EQW)
3013 	return false;
3014       v[s-1]._EQWptr->selected=select;
3015       gen sommet=v[s-1]._EQWptr->g;
3016       --s;
3017       vecteur args(s);
3018       for (size_t i=0;i<s;++i){
3019 	if (!do_select(v[i],select,args[i]))
3020 	  return false;
3021 	if (args[i].type==_EQW)
3022 	  args[i]=args[i]._EQWptr->g;
3023       }
3024       gen va=s==1?args[0]:gen(args,_SEQ__VECT);
3025       if (sommet.type==_FUNC)
3026 	va=symbolic(*sommet._FUNCptr,va);
3027       else
3028 	va=sommet(va,context0);
3029       //cout << "va " << va << endl;
3030       value=*v[s]._EQWptr;
3031       value._EQWptr->g=va;
3032       //cout << "value " << value << endl;
3033       return true;
3034     }
3035     if (eql.type!=_EQW)
3036       return false;
3037     eql._EQWptr->selected=select;
3038     value=eql;
3039     return true;
3040   }
3041 
Equation_box_sizes(const gen & g,int & l,int & h,int & x,int & y,attributs & attr,bool & selected)3042   bool Equation_box_sizes(const gen & g,int & l,int & h,int & x,int & y,attributs & attr,bool & selected){
3043     if (g.type==_EQW){
3044       eqwdata & w=*g._EQWptr;
3045       x=w.x;
3046       y=w.y;
3047       l=w.dx;
3048       h=w.dy;
3049       selected=w.selected;
3050       attr=w.eqw_attributs;
3051       //cout << g << endl;
3052       return true;
3053     }
3054     else {
3055       if (g.type!=_VECT || g._VECTptr->empty() ){
3056 	l=0;
3057 	h=0;
3058 	x=0;
3059 	y=0;
3060 	attr=attributs(0,0,0);
3061 	selected=false;
3062 	return true;
3063       }
3064       gen & g1=g._VECTptr->back();
3065       Equation_box_sizes(g1,l,h,x,y,attr,selected);
3066       return false;
3067     }
3068   }
3069 
3070   // return true if g has some selection inside, gsel points to the selection
Equation_adjust_xy(gen & g,int & xleft,int & ytop,int & xright,int & ybottom,gen * & gsel,gen * & gselparent,int & gselpos,std::vector<int> * goto_ptr)3071   bool Equation_adjust_xy(gen & g,int & xleft,int & ytop,int & xright,int & ybottom,gen * & gsel,gen * & gselparent,int &gselpos,std::vector<int> * goto_ptr){
3072     gsel=0;
3073     gselparent=0;
3074     gselpos=0;
3075     int x,y,w,h;
3076     attributs f(0,0,0);
3077     bool selected;
3078     Equation_box_sizes(g,w,h,x,y,f,selected);
3079     if ( (g.type==_EQW__VECT) || selected ){ // terminal or selected
3080       xleft=x;
3081       ybottom=y;
3082       if (selected){ // g is selected
3083 	ytop=y+h;
3084 	xright=x+w;
3085 	gsel =  &g;
3086 	//cout << "adjust " << *gsel << endl;
3087 	return true;
3088       }
3089       else { // no selection
3090 	xright=x;
3091 	ytop=y;
3092 	return false;
3093       }
3094     }
3095     if (g.type!=_VECT)
3096       return false;
3097     // last not selected, recurse
3098     iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end()-1;
3099     for (;it!=itend;++it){
3100       if (Equation_adjust_xy(*it,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,goto_ptr)){
3101 	if (goto_ptr){
3102 	  goto_ptr->push_back(it-g._VECTptr->begin());
3103 	  //cout << g << ":" << *goto_ptr << endl;
3104 	}
3105 	if (gsel==&*it){
3106 	  // check next siblings
3107 
3108 	  gselparent= &g;
3109 	  gselpos=it-g._VECTptr->begin();
3110 	  //cout << "gselparent " << g << endl;
3111 	}
3112 	return true;
3113       }
3114     }
3115     return false;
3116   }
3117 
3118   // select or deselect part of the current eqution
3119   // This is done *in place*
Equation_select(gen & g,bool select)3120   void Equation_select(gen & g,bool select){
3121     if (g.type==_EQW){
3122       eqwdata & e=*g._EQWptr;
3123       e.selected=select;
3124     }
3125     if (g.type!=_VECT)
3126       return;
3127     vecteur & v=*g._VECTptr;
3128     iterateur it=v.begin(),itend=v.end();
3129     for (;it!=itend;++it)
3130       Equation_select(*it,select);
3131   }
3132 
3133   // decrease selection (like HP49 eqw Down key)
eqw_select_down(gen & g)3134   int eqw_select_down(gen & g){
3135     int xleft,ytop,xright,ybottom,gselpos;
3136     int newxleft,newytop,newxright,newybottom;
3137     gen * gsel,*gselparent;
3138     if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos)){
3139       //cout << "select down before " << *gsel << endl;
3140       if (gsel->type==_VECT && !gsel->_VECTptr->empty()){
3141 	Equation_select(*gsel,false);
3142 	Equation_select(gsel->_VECTptr->front(),true);
3143 	//cout << "select down after " << *gsel << endl;
3144 	Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos);
3145 	return newytop-ytop;
3146       }
3147     }
3148     return 0;
3149   }
3150 
eqw_select_up(gen & g)3151   int eqw_select_up(gen & g){
3152     int xleft,ytop,xright,ybottom,gselpos;
3153     int newxleft,newytop,newxright,newybottom;
3154     gen * gsel,*gselparent;
3155     if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos) && gselparent){
3156       Equation_select(*gselparent,true);
3157       //cout << "gselparent " << *gselparent << endl;
3158       Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos);
3159       return newytop-ytop;
3160     }
3161     return false;
3162   }
3163 
3164   // exchange==0 move selection to left or right sibling, ==2 add left or right
3165   // sibling, ==1 exchange selection with left or right sibling
eqw_select_leftright(Equation & eq,bool left,int exchange,GIAC_CONTEXT)3166   int eqw_select_leftright(Equation & eq,bool left,int exchange,GIAC_CONTEXT){
3167     gen & g=eq.data;
3168     int xleft,ytop,xright,ybottom,gselpos;
3169     int newxleft,newytop,newxright,newybottom;
3170     gen * gsel,*gselparent;
3171     vector<int> goto_sel;
3172     if (Equation_adjust_xy(g,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gselparent && gselparent->type==_VECT){
3173       vecteur & gselv=*gselparent->_VECTptr;
3174       int n=gselv.size()-1,gselpos_orig=gselpos;
3175       if (n<1) return 0;
3176       if (left) {
3177 	if (gselpos==0)
3178 	  gselpos=n-1;
3179 	else
3180 	  gselpos--;
3181       }
3182       else {
3183 	if (gselpos==n-1)
3184 	  gselpos=0;
3185 	else
3186 	  gselpos++;
3187       }
3188       if (exchange==1){ // exchange gselpos_orig and gselpos
3189 	swapgen(gselv[gselpos],gselv[gselpos_orig]);
3190 	gsel=&gselv[gselpos_orig];
3191 	gen value;
3192 	if (xcas::do_select(*gsel,true,value) && value.type==_EQW)
3193 	  replace_selection(eq,value._EQWptr->g,gsel,&goto_sel,contextptr);
3194       }
3195       else {
3196 	// increase selection to next sibling possible for + and * only
3197 	if (n>2 && exchange==2 && gselv[n].type==_EQW && (gselv[n]._EQWptr->g==at_plus || gselv[n]._EQWptr->g==at_prod)){
3198 	  gen value1, value2,tmp;
3199 	  if (gselpos_orig<gselpos)
3200 	    swapint(gselpos_orig,gselpos);
3201 	  // now gselpos<gselpos_orig
3202 	  xcas::do_select(gselv[gselpos_orig],true,value1);
3203 	  xcas::do_select(gselv[gselpos],true,value2);
3204 	  if (value1.type==_EQW && value2.type==_EQW){
3205 	    tmp=gselv[n]._EQWptr->g==at_plus?value1._EQWptr->g+value2._EQWptr->g:value1._EQWptr->g*value2._EQWptr->g;
3206 	    gselv.erase(gselv.begin()+gselpos_orig);
3207 	    replace_selection(eq,tmp,&gselv[gselpos],&goto_sel,contextptr);
3208 	  }
3209 	}
3210 	else {
3211 	  Equation_select(*gselparent,false);
3212 	  gen & tmp=(*gselparent->_VECTptr)[gselpos];
3213 	  Equation_select(tmp,true);
3214 	}
3215       }
3216       Equation_adjust_xy(g,newxleft,newytop,newxright,newybottom,gsel,gselparent,gselpos);
3217       return newxleft-xleft;
3218     }
3219     return 0;
3220   }
3221 
eqw_select(const gen & eq,int l,int c,bool select,gen & value)3222   bool eqw_select(const gen & eq,int l,int c,bool select,gen & value){
3223     value=undef;
3224     if (l<0 || eq.type!=_VECT || eq._VECTptr->size()<=l)
3225       return false;
3226     gen & eql=(*eq._VECTptr)[l];
3227     if (c<0)
3228       return do_select(eql,select,value);
3229     if (eql.type!=_VECT || eql._VECTptr->size()<=c)
3230       return false;
3231     gen & eqlc=(*eql._VECTptr)[c];
3232     return do_select(eqlc,select,value);
3233   }
3234 
3235   gen Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT);
3236 
3237   // void Bdisp_MMPrint(int x, int y, const char* string, int mode_flags, int xlimit, int P6, int P7, int color, int back_color, int writeflag, int P11);
3238   // void PrintCXY(int x, int y, const char *cptr, int mode_flags, int P5, int color, int back_color, int P8, int P9)
3239   // void PrintMini( int* x, int* y, const char* string, int mode_flags, unsigned int xlimit, int P6, int P7, int color, int back_color, int writeflag, int P11)
text_print(int fontsize,const char * s,int x,int y,int c=COLOR_BLACK,int bg=COLOR_WHITE,int mode=0)3240   void text_print(int fontsize,const char * s,int x,int y,int c=COLOR_BLACK,int bg=COLOR_WHITE,int mode=0){
3241     // *logptr(contextptr) << x << " " << y << " " << fontsize << " " << s << endl; return;
3242     c=(unsigned short) c;
3243     if (x>LCD_WIDTH_PX) return;
3244     int ss=strlen(s);
3245     if (ss==1 && s[0]==0x1e){ // arrow for limit
3246       if (mode==4)
3247 	c=bg;
3248       draw_line(x,y-4,x+fontsize/2,y-4,c);
3249       draw_line(x,y-3,x+fontsize/2,y-3,c);
3250       draw_line(x+fontsize/2-4,y,x+fontsize/2,y-4,c);
3251       draw_line(x+fontsize/2-3,y,x+fontsize/2+1,y-4,c);
3252       draw_line(x+fontsize/2-4,y-7,x+fontsize/2,y-3,c);
3253       draw_line(x+fontsize/2-3,y-7,x+fontsize/2+1,y-3,c);
3254       return;
3255     }
3256     if (ss==2 && strcmp(s,"pi")==0){
3257       if (mode==4){
3258 	drawRectangle(x,y+2-fontsize,fontsize,fontsize,c);
3259 	c=bg;
3260       }
3261       draw_line(x+fontsize/3-1,y+1,x+fontsize/3,y+6-fontsize,c);
3262       draw_line(x+fontsize/3-2,y+1,x+fontsize/3-1,y+6-fontsize,c);
3263       draw_line(x+2*fontsize/3,y+1,x+2*fontsize/3,y+6-fontsize,c);
3264       draw_line(x+2*fontsize/3+1,y+1,x+2*fontsize/3+1,y+6-fontsize,c);
3265       draw_line(x+2,y+6-fontsize,x+fontsize,y+6-fontsize,c);
3266       draw_line(x+2,y+5-fontsize,x+fontsize,y+5-fontsize,c);
3267       return;
3268     }
3269     if (fontsize>=16 && ss==2 && s[0]==char(0xe5) && (s[1]==char(0xea) || s[1]==char(0xeb))) // special handling for increasing and decreasing in tabvar output
3270       fontsize=18;
3271     if (fontsize>=18){
3272       y -= 16;// status area shift
3273       os_draw_string(x,y,mode==4?bg:c,mode==4?c:bg,s);
3274       // PrintMini(&x,&y,(unsigned char *)s,mode,0xffffffff,0,0,c,bg,1,0);
3275       return;
3276     }
3277     y -= 12;
3278     x=os_draw_string_small(x,y,mode==4?bg:c,mode==4?c:bg,s);// PrintMiniMini( &x, &y, (unsigned char *)s, mode,c, 0 );
3279     return;
3280   }
3281 
text_width(int fontsize,const char * s)3282   int text_width(int fontsize,const char * s){
3283 #ifdef NSPIRE_NEWLIB
3284     int x=0;
3285     if (fontsize>=18)
3286       x=os_draw_string(0,0,0,1,s,true);
3287     else
3288       x=os_draw_string_small(0,0,0,1,s,true);
3289     return x;
3290 #else
3291     if (fontsize>=18)
3292       return strlen(s)*11;
3293     return strlen(s)*7;
3294 #endif
3295   }
3296 
fl_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK)3297   void fl_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK){
3298     rx/=2;
3299     ry/=2;
3300     // *logptr(contextptr) << "theta " << theta1_deg << " " << theta2_deg << endl;
3301     if (ry==rx){
3302       if (theta2_deg-theta1_deg==360){
3303 	draw_circle(x+rx,y+rx,rx,c);
3304 	return;
3305       }
3306       if (theta1_deg==0 && theta2_deg==180){
3307 	draw_circle(x+rx,y+rx,rx,c,true,true,false,false);
3308 	return;
3309       }
3310       if (theta1_deg==180 && theta2_deg==360){
3311 	draw_circle(x+rx,y+rx,rx,c,false,false,true,true);
3312 	return;
3313       }
3314     }
3315     // *logptr(contextptr) << "draw_arc" << theta1_deg*M_PI/180. << " " << theta2_deg*M_PI/180. << endl;
3316     draw_arc(x+rx,y+ry,rx,ry,c,theta1_deg*M_PI/180.,theta2_deg*M_PI/180.,context0);
3317   }
3318 
fl_pie(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK,bool segment=false)3319   void fl_pie(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int c=COLOR_BLACK,bool segment=false){
3320     //cout << "fl_pie " << theta1_deg << " " << theta2_deg << " " << c << endl;
3321     if (!segment && ry==rx){
3322       if (theta2_deg-theta1_deg>=360){
3323 	rx/=2;
3324 	draw_filled_circle(x+rx,y+rx,rx,c);
3325 	return;
3326       }
3327       if (theta1_deg==-90 && theta2_deg==90){
3328 	rx/=2;
3329 	draw_filled_circle(x+rx,y+rx,rx,c,false,true);
3330 	return;
3331       }
3332       if (theta1_deg==90 && theta2_deg==270){
3333 	rx/=2;
3334 	draw_filled_circle(x+rx,y+rx,rx,c,true,false);
3335 	return;
3336       }
3337     }
3338     // approximation by a filled polygon
3339     // points: (x,y), (x+rx*cos(theta)/2,y+ry*sin(theta)/2) theta=theta1..theta2
3340     while (theta2_deg<theta1_deg)
3341       theta2_deg+=360;
3342     if (theta2_deg-theta1_deg>=360){
3343       theta1_deg=0;
3344       theta2_deg=360;
3345     }
3346     int N0=theta2_deg-theta1_deg+1;
3347     // reduce N if rx or ry is small
3348     double red=double(rx)/LCD_WIDTH_PX*double(ry)/LCD_HEIGHT_PX;
3349     if (red>1) red=1;
3350     if (red<0.1) red=0.1;
3351     int N=red*N0;
3352     if (N<5)
3353       N=N0>5?5:N0;
3354     if (N<2)
3355       N=2;
3356     vector< vector<int> > v(segment?N+1:N+2,vector<int>(2));
3357     x += rx/2;
3358     y += ry/2;
3359     int i=0;
3360     if (!segment){
3361       v[0][0]=x;
3362       v[0][1]=y;
3363       ++i;
3364     }
3365     double theta=theta1_deg*M_PI/180;
3366     double thetastep=(theta2_deg-theta1_deg)*M_PI/(180*(N-1));
3367     for (;i<v.size()-1;++i){
3368       v[i][0]=int(x+rx*std::cos(theta)/2+.5);
3369       v[i][1]=int(y-ry*std::sin(theta)/2+.5); // y is inverted
3370       theta += thetastep;
3371     }
3372     v.back()=v.front();
3373     draw_filled_polygon(v,0,LCD_WIDTH_PX,24,LCD_HEIGHT_PX,c);
3374   }
3375 
binary_op(const unary_function_ptr & u)3376   bool binary_op(const unary_function_ptr & u){
3377     const unary_function_ptr binary_op_tab_ptr []={*at_plus,*at_prod,*at_pow,*at_and,*at_ou,*at_xor,*at_different,*at_same,*at_equal,*at_unit,*at_compose,*at_composepow,*at_deuxpoints,*at_tilocal,*at_pointprod,*at_pointdivision,*at_pointpow,*at_division,*at_normalmod,*at_minus,*at_intersect,*at_union,*at_interval,*at_inferieur_egal,*at_inferieur_strict,*at_superieur_egal,*at_superieur_strict,*at_equal2,0};
3378     return equalposcomp(binary_op_tab_ptr,u);
3379   }
3380 
Equation_total_size(const gen & g)3381   eqwdata Equation_total_size(const gen & g){
3382     if (g.type==_EQW)
3383       return *g._EQWptr;
3384     if (g.type!=_VECT || g._VECTptr->empty())
3385       return eqwdata(0,0,0,0,attributs(0,0,0),undef);
3386     return Equation_total_size(g._VECTptr->back());
3387   }
3388 
3389   // find smallest value of y and height
Equation_y_dy(const gen & g,int & y,int & dy)3390   void Equation_y_dy(const gen & g,int & y,int & dy){
3391     y=0; dy=0;
3392     if (g.type==_EQW){
3393       y=g._EQWptr->y;
3394       dy=g._EQWptr->dy;
3395     }
3396     if (g.type==_VECT){
3397       iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
3398       for (;it!=itend;++it){
3399 	int Y,dY;
3400 	Equation_y_dy(*it,Y,dY);
3401 	// Y, Y+dY and y,y+dy
3402 	int ymax=giacmax(y+dy,Y+dY);
3403 	if (Y<y)
3404 	  y=Y;
3405 	dy=ymax-y;
3406       }
3407     }
3408   }
3409 
Equation_translate(gen & g,int deltax,int deltay)3410   void Equation_translate(gen & g,int deltax,int deltay){
3411     if (g.type==_EQW){
3412       g._EQWptr->x += deltax;
3413       g._EQWptr->y += deltay;
3414       g._EQWptr->baseline += deltay;
3415       return ;
3416     }
3417     if (g.type!=_VECT)
3418       setsizeerr();
3419     vecteur & v=*g._VECTptr;
3420     iterateur it=v.begin(),itend=v.end();
3421     for (;it!=itend;++it)
3422       Equation_translate(*it,deltax,deltay);
3423   }
3424 
Equation_change_attributs(const gen & g,const attributs & newa)3425   gen Equation_change_attributs(const gen & g,const attributs & newa){
3426     if (g.type==_EQW){
3427       gen res(*g._EQWptr);
3428       res._EQWptr->eqw_attributs = newa;
3429       return res;
3430     }
3431     if (g.type!=_VECT)
3432       return gensizeerr();
3433     vecteur v=*g._VECTptr;
3434     iterateur it=v.begin(),itend=v.end();
3435     for (;it!=itend;++it)
3436       *it=Equation_change_attributs(*it,newa);
3437     return gen(v,g.subtype);
3438   }
3439 
Equation_subsizes(const gen & arg,const attributs & a,int windowhsize,GIAC_CONTEXT)3440   vecteur Equation_subsizes(const gen & arg,const attributs & a,int windowhsize,GIAC_CONTEXT){
3441     vecteur v;
3442     if ( (arg.type==_VECT) && ( (arg.subtype==_SEQ__VECT)
3443 				// || (!ckmatrix(arg))
3444 				) ){
3445       const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end();
3446       for (;it!=itend;++it)
3447 	v.push_back(Equation_compute_size(*it,a,windowhsize,contextptr));
3448     }
3449     else {
3450       v.push_back(Equation_compute_size(arg,a,windowhsize,contextptr));
3451     }
3452     return v;
3453   }
3454 
3455   // vertical merge with same baseline
3456   // for vertical merge of hp,yp at top (like ^) add fontsize to yp
3457   // at bottom (like lower bound of int) substract fontsize from yp
Equation_vertical_adjust(int hp,int yp,int & h,int & y)3458   void Equation_vertical_adjust(int hp,int yp,int & h,int & y){
3459     int yf=min(y,yp);
3460     h=max(y+h,yp+hp)-yf;
3461     y=yf;
3462   }
3463 
Equation_compute_symb_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT)3464   gen Equation_compute_symb_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){
3465     if (g.type!=_SYMB)
3466       return Equation_compute_size(g,a,windowhsize,contextptr);
3467     unary_function_ptr & u=g._SYMBptr->sommet;
3468     gen arg=g._SYMBptr->feuille,rootof_value;
3469     if (u==at_makevector){
3470       vecteur v(1,arg);
3471       if (arg.type==_VECT)
3472 	v=*arg._VECTptr;
3473       iterateur it=v.begin(),itend=v.end();
3474       for (;it!=itend;++it){
3475 	if ( (it->type==_SYMB) && (it->_SYMBptr->sommet==at_makevector) )
3476 	  *it=_makevector(it->_SYMBptr->feuille,contextptr);
3477       }
3478       return Equation_compute_size(v,a,windowhsize,contextptr);
3479     }
3480     if (u==at_makesuite){
3481       if (arg.type==_VECT)
3482 	return Equation_compute_size(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr);
3483       else
3484 	return Equation_compute_size(arg,a,windowhsize,contextptr);
3485     }
3486     if (u==at_sqrt)
3487       return Equation_compute_size(symb_pow(arg,plus_one_half),a,windowhsize,contextptr);
3488     if (u==at_division){
3489       if (arg.type!=_VECT || arg._VECTptr->size()!=2)
3490 	return Equation_compute_size(arg,a,windowhsize,contextptr);
3491       gen tmp=Tfraction<gen>(arg._VECTptr->front(),arg._VECTptr->back());
3492       return Equation_compute_size(tmp,a,windowhsize,contextptr);
3493     }
3494     if (u==at_prod){
3495       gen n,d;
3496       if (rewrite_prod_inv(arg,n,d)){
3497 	if (n.is_symb_of_sommet(at_neg))
3498 	  return Equation_compute_size(symbolic(at_neg,Tfraction<gen>(-n,d)),a,windowhsize,contextptr);
3499 	return Equation_compute_size(Tfraction<gen>(n,d),a,windowhsize,contextptr);
3500       }
3501     }
3502     if (u==at_inv){
3503       if ( (is_integer(arg) && is_positive(-arg,contextptr))
3504 	   || (arg.is_symb_of_sommet(at_neg)))
3505 	return Equation_compute_size(symbolic(at_neg,Tfraction<gen>(plus_one,-arg)),a,windowhsize,contextptr);
3506       return Equation_compute_size(Tfraction<gen>(plus_one,arg),a,windowhsize,contextptr);
3507     }
3508     if (u==at_expr && arg.type==_VECT && arg.subtype==_SEQ__VECT && arg._VECTptr->size()==2 && arg._VECTptr->back().type==_INT_){
3509       gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
3510       eqwdata vv(Equation_total_size(varg1));
3511       gen varg2=eqwdata(0,0,0,0,a,arg._VECTptr->back());
3512       vecteur v12(makevecteur(varg1,varg2));
3513       v12.push_back(eqwdata(vv.dx,vv.dy,0,vv.y,a,at_expr,0));
3514       return gen(v12,_SEQ__VECT);
3515     }
3516     int llp=int(text_width(a.fontsize,("(")))-1;
3517     int lrp=llp;
3518     int lc=int(text_width(a.fontsize,(",")));
3519     string us=u.ptr()->s;
3520     int ls=int(text_width(a.fontsize,(us.c_str())));
3521     // if (isalpha(u.ptr()->s[0])) ls += 1;
3522     if (u==at_abs)
3523       ls = 2;
3524     // special cases first int, sigma, /, ^
3525     // and if printed as printsommetasoperator
3526     // otherwise print with usual functional notation
3527     int x=0;
3528     int h=a.fontsize;
3529     int y=0;
3530 #if 1
3531     if ((u==at_integrate) || (u==at_sum) ){ // Int
3532       int s=1;
3533       if (arg.type==_VECT)
3534 	s=arg._VECTptr->size();
3535       else
3536 	arg=vecteur(1,arg);
3537       // s==1 -> general case
3538       if ( (s==1) || (s==2) ){ // int f(x) dx and sum f(n) n
3539 	vecteur v(Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr));
3540 	eqwdata vv(Equation_total_size(v[0]));
3541 	if (s==1){
3542 	  x=a.fontsize;
3543 	  Equation_translate(v[0],x,0);
3544 	  x += int(text_width(a.fontsize,(" dx")));
3545 	}
3546 	if (s==2){
3547 	  if (u==at_integrate){
3548 	    x=a.fontsize;
3549 	    Equation_translate(v[0],x,0);
3550 	    x += vv.dx+int(text_width(a.fontsize,(" d")));
3551 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
3552 	    vv=Equation_total_size(v[1]);
3553 	    Equation_translate(v[1],x,0);
3554 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
3555 	  }
3556 	  else {
3557 	    Equation_vertical_adjust(vv.dy,vv.y,h,y);
3558 	    eqwdata v1=Equation_total_size(v[1]);
3559 	    x=max((int)a.fontsize,(int)v1.dx)+2*a.fontsize/3; // var name size
3560 	    Equation_translate(v[1],0,-v1.dy-v1.y);
3561 	    Equation_vertical_adjust(v1.dy,-v1.dy,h,y);
3562 	    Equation_translate(v[0],x,0);
3563 	    x += vv.dx; // add function size
3564 	  }
3565 	}
3566 	if (u==at_integrate){
3567 	  x += vv.dx;
3568 	  if (h==a.fontsize)
3569 	    h+=2*a.fontsize/3;
3570 	  if (y==0){
3571 	    y=-2*a.fontsize/3;
3572 	    h+=2*a.fontsize/3;
3573 	  }
3574 	}
3575 	v.push_back(eqwdata(x,h,0,y,a,u,0));
3576 	return gen(v,_SEQ__VECT);
3577       }
3578       if (s>=3){ // int _a^b f(x) dx
3579 	vecteur & intarg=*arg._VECTptr;
3580 	gen tmp_l,tmp_u,tmp_f,tmp_x;
3581 	attributs aa(a);
3582 	if (a.fontsize>=10)
3583 	  aa.fontsize -= 2;
3584 	tmp_f=Equation_compute_size(intarg[0],a,windowhsize,contextptr);
3585 	tmp_x=Equation_compute_size(intarg[1],a,windowhsize,contextptr);
3586 	tmp_l=Equation_compute_size(intarg[2],aa,windowhsize,contextptr);
3587 	if (s==4)
3588 	  tmp_u=Equation_compute_size(intarg[3],aa,windowhsize,contextptr);
3589 	x=a.fontsize+(u==at_integrate?-2:+4);
3590 	eqwdata vv(Equation_total_size(tmp_l));
3591 	Equation_translate(tmp_l,x,-vv.y-vv.dy);
3592 	vv=Equation_total_size(tmp_l);
3593 	Equation_vertical_adjust(vv.dy,vv.y,h,y);
3594 	int lx = vv.dx;
3595 	if (s==4){
3596 	  vv=Equation_total_size(tmp_u);
3597 	  Equation_translate(tmp_u,x,a.fontsize-3-vv.y);
3598 	  vv=Equation_total_size(tmp_u);
3599 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
3600 	}
3601 	x += max(lx,(int)vv.dx);
3602 	Equation_translate(tmp_f,x,0);
3603 	vv=Equation_total_size(tmp_f);
3604 	Equation_vertical_adjust(vv.dy,vv.y,h,y);
3605 	if (u==at_integrate){
3606 	  x += vv.dx+int(text_width(a.fontsize,(" d")));
3607 	  Equation_translate(tmp_x,x,0);
3608 	  vv=Equation_total_size(tmp_x);
3609 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
3610 	  x += vv.dx;
3611 	}
3612 	else {
3613 	  x += vv.dx;
3614 	  Equation_vertical_adjust(vv.dy,vv.y,h,y);
3615 	  vv=Equation_total_size(tmp_x);
3616 	  x=max(x,(int)vv.dx)+a.fontsize/3;
3617 	  Equation_translate(tmp_x,0,-vv.dy-vv.y);
3618 	  //Equation_translate(tmp_l,0,-1);
3619 	  if (s==4) Equation_translate(tmp_u,-2,0);
3620 	  Equation_vertical_adjust(vv.dy,-vv.dy,h,y);
3621 	}
3622 	vecteur res(makevecteur(tmp_f,tmp_x,tmp_l));
3623 	if (s==4)
3624 	  res.push_back(tmp_u);
3625 	res.push_back(eqwdata(x,h,0,y,a,u,0));
3626 	return gen(res,_SEQ__VECT);
3627       }
3628     }
3629     if (u==at_limit && arg.type==_VECT){ // limit
3630       vecteur limarg=*arg._VECTptr;
3631       int s=limarg.size();
3632       if (s==2 && limarg[1].is_symb_of_sommet(at_equal)){
3633 	limarg.push_back(limarg[1]._SYMBptr->feuille[1]);
3634 	limarg[1]=limarg[1]._SYMBptr->feuille[0];
3635 	++s;
3636       }
3637       if (s>=3){
3638 	gen tmp_l,tmp_f,tmp_x,tmp_dir;
3639 	attributs aa(a);
3640 	if (a.fontsize>=10)
3641 	  aa.fontsize -= 2;
3642 	tmp_f=Equation_compute_size(limarg[0],a,windowhsize,contextptr);
3643 	tmp_x=Equation_compute_size(limarg[1],aa,windowhsize,contextptr);
3644 	tmp_l=Equation_compute_size(limarg[2],aa,windowhsize,contextptr);
3645 	if (s==4)
3646 	  tmp_dir=Equation_compute_size(limarg[3],aa,windowhsize,contextptr);
3647 	eqwdata vf(Equation_total_size(tmp_f));
3648 	eqwdata vx(Equation_total_size(tmp_x));
3649 	eqwdata vl(Equation_total_size(tmp_l));
3650 	eqwdata vdir(Equation_total_size(tmp_dir));
3651 	int sous=max(vx.dy,vl.dy);
3652 	if (s==4)
3653 	  Equation_translate(tmp_f,vx.dx+vl.dx+vdir.dx+a.fontsize+4,0);
3654 	else
3655 	  Equation_translate(tmp_f,vx.dx+vl.dx+a.fontsize+2,0);
3656 	Equation_translate(tmp_x,0,-sous-vl.y);
3657 	Equation_translate(tmp_l,vx.dx+a.fontsize+2,-sous-vl.y);
3658 	if (s==4)
3659 	  Equation_translate(tmp_dir,vx.dx+vl.dx+a.fontsize+4,-sous-vl.y);
3660 	h=vf.dy;
3661 	y=vf.y;
3662 	vl=Equation_total_size(tmp_l);
3663 	Equation_vertical_adjust(vl.dy,vl.y,h,y);
3664 	vecteur res(makevecteur(tmp_f,tmp_x,tmp_l));
3665 	if (s==4){
3666 	  res.push_back(tmp_dir);
3667 	  res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+4+vl.dx+vdir.dx,h,0,y,a,u,0));
3668 	}
3669 	else
3670 	  res.push_back(eqwdata(vf.dx+vx.dx+a.fontsize+2+vl.dx,h,0,y,a,u,0));
3671 	return gen(res,_SEQ__VECT);
3672       }
3673     }
3674 #endif
3675     if ( (u==at_of || u==at_at) && arg.type==_VECT && arg._VECTptr->size()==2 ){
3676       // user function, function in 1st arg, arguments in 2nd arg
3677       gen varg1=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
3678       eqwdata vv=Equation_total_size(varg1);
3679       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3680       gen arg2=arg._VECTptr->back();
3681       if (u==at_at && xcas_mode(contextptr)!=0){
3682 	if (arg2.type==_VECT)
3683 	  arg2=gen(addvecteur(*arg2._VECTptr,vecteur(arg2._VECTptr->size(),plus_one)),_SEQ__VECT);
3684 	else
3685 	  arg2=arg2+plus_one;
3686       }
3687       gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr);
3688       Equation_translate(varg2,vv.dx+llp,0);
3689       vv=Equation_total_size(varg2);
3690       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3691       vecteur res(makevecteur(varg1,varg2));
3692       res.push_back(eqwdata(vv.dx+vv.x+lrp,h,0,y,a,u,0));
3693       return gen(res,_SEQ__VECT);
3694     }
3695     if (u==at_pow){
3696       // first arg not translated
3697       gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
3698       eqwdata vv=Equation_total_size(varg);
3699       // 1/2 ->sqrt, otherwise as exponent
3700       if (arg._VECTptr->back()==plus_one_half){
3701 	Equation_translate(varg,a.fontsize,0);
3702 	vecteur res(1,varg);
3703 	res.push_back(eqwdata(vv.dx+a.fontsize,vv.dy+4,vv.x,vv.y,a,at_sqrt,0));
3704 	return gen(res,_SEQ__VECT);
3705       }
3706       bool needpar=vv.g.type==_FUNC || vv.g.is_symb_of_sommet(at_pow) || need_parenthesis(vv.g);
3707       if (needpar)
3708 	x=llp;
3709       Equation_translate(varg,x,0);
3710       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3711       vecteur res(1,varg);
3712       // 2nd arg translated
3713       if (needpar)
3714 	x+=vv.dx+lrp;
3715       else
3716 	x+=vv.dx+1;
3717       int arg1dy=vv.dy,arg1y=vv.y;
3718       if (a.fontsize>=16){
3719 	attributs aa(a);
3720 	aa.fontsize -= 2;
3721 	varg=Equation_compute_size(arg._VECTptr->back(),aa,windowhsize,contextptr);
3722       }
3723       else
3724 	varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
3725       vv=Equation_total_size(varg);
3726       Equation_translate(varg,x,arg1y+(3*arg1dy)/4-vv.y);
3727       res.push_back(varg);
3728       vv=Equation_total_size(varg);
3729       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3730       x += vv.dx;
3731       res.push_back(eqwdata(x,h,0,y,a,u,0));
3732       return gen(res,_SEQ__VECT);
3733     }
3734     if (u==at_factorial){
3735       vecteur v;
3736       gen varg=Equation_compute_size(arg,a,windowhsize,contextptr);
3737       eqwdata vv=Equation_total_size(varg);
3738       bool paren=need_parenthesis(vv.g) || vv.g==at_prod || vv.g==at_division || vv.g==at_pow;
3739       if (paren)
3740 	x+=llp;
3741       Equation_translate(varg,x,0);
3742       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3743       v.push_back(varg);
3744       x += vv.dx;
3745       if (paren)
3746 	x+=lrp;
3747       varg=eqwdata(x+4,h,0,y,a,u,0);
3748       v.push_back(varg);
3749       return gen(v,_SEQ__VECT);
3750     }
3751     if (u==at_sto){ // A:=B, *it -> B
3752       gen varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
3753       eqwdata vv=Equation_total_size(varg);
3754       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3755       Equation_translate(varg,x,0);
3756       vecteur v(2);
3757       v[1]=varg;
3758       x+=vv.dx;
3759       x+=ls+3;
3760       // first arg not translated
3761       varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
3762       vv=Equation_total_size(varg);
3763       if (need_parenthesis(vv.g))
3764 	x+=llp;
3765       Equation_translate(varg,x,0);
3766       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3767       v[0]=varg;
3768       x += vv.dx;
3769       if (need_parenthesis(vv.g))
3770 	x+=lrp;
3771       v.push_back(eqwdata(x,h,0,y,a,u,0));
3772       return gen(v,_SEQ__VECT);
3773     }
3774     if (u==at_program && arg._VECTptr->back().type!=_VECT && !arg._VECTptr->back().is_symb_of_sommet(at_local) ){
3775       gen varg=Equation_compute_size(arg._VECTptr->front(),a,windowhsize,contextptr);
3776       eqwdata vv=Equation_total_size(varg);
3777       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3778       Equation_translate(varg,x,0);
3779       vecteur v(2);
3780       v[0]=varg;
3781       x+=vv.dx;
3782       x+=int(text_width(a.fontsize,("->")))+3;
3783       varg=Equation_compute_size(arg._VECTptr->back(),a,windowhsize,contextptr);
3784       vv=Equation_total_size(varg);
3785       Equation_translate(varg,x,0);
3786       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3787       v[1]=varg;
3788       x += vv.dx;
3789       v.push_back(eqwdata(x,h,0,y,a,u,0));
3790       return gen(v,_SEQ__VECT);
3791     }
3792     bool binaryop= (u.ptr()->printsommet==&printsommetasoperator) || binary_op(u);
3793     if ( u!=at_sto && u.ptr()->printsommet!=NULL && !binaryop ){
3794       gen tmp=string2gen(g.print(contextptr),false);
3795       return Equation_compute_size(symbolic(at_expr,makesequence(tmp,xcas_mode(contextptr))),a,windowhsize,contextptr);
3796     }
3797     vecteur v;
3798     if (!binaryop || arg.type!=_VECT)
3799       v=Equation_subsizes(arg,a,windowhsize,contextptr);
3800     else
3801       v=Equation_subsizes(gen(*arg._VECTptr,_SEQ__VECT),a,windowhsize,contextptr);
3802     iterateur it=v.begin(),itend=v.end();
3803     if ( it==itend || (itend-it==1) ){
3804       gen gtmp;
3805       if (it==itend)
3806 	gtmp=Equation_compute_size(gen(vecteur(0),_SEQ__VECT),a,windowhsize,contextptr);
3807       else
3808 	gtmp=*it;
3809       // unary op, shift arg position horizontally
3810       eqwdata vv=Equation_total_size(gtmp);
3811       bool paren = u!=at_neg || (vv.g!=at_prod && need_parenthesis(vv.g)) ;
3812       x=ls+(paren?llp:0);
3813       gen tmp=gtmp; Equation_translate(tmp,x,0);
3814       x=x+vv.dx+(paren?lrp:0);
3815       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3816       return gen(makevecteur(tmp,eqwdata(x,h,0,y,a,u,0)),_EQW__VECT);
3817     }
3818     if (binaryop){ // op (default with par)
3819       int currenth=h,largeur=0;
3820       iterateur itprec=v.begin();
3821       h=0;
3822       if (u==at_plus){ // op without parenthesis
3823 	if (it->type==_VECT && !it->_VECTptr->empty() && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_equal)
3824 	  ;
3825 	else {
3826 	  llp=0;
3827 	  lrp=0;
3828 	}
3829       }
3830       for (;;){
3831 	eqwdata vv=Equation_total_size(*it);
3832 	if (need_parenthesis(vv.g))
3833 	  x+=llp;
3834 	if (u==at_plus && it!=v.begin() &&
3835 	    (
3836 	     (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg)
3837 	     ||
3838 	     ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) )
3839 	      )
3840 	    )
3841 	  x -= ls;
3842 #if 0 //
3843 	if (x>windowhsize-vv.dx && x>windowhsize/2 && (itend-it)*vv.dx>windowhsize/2){
3844 	  largeur=max(x,largeur);
3845 	  x=0;
3846 	  if (need_parenthesis(vv.g))
3847 	    x+=llp;
3848 	  h+=currenth;
3849 	  Equation_translate(*it,x,0);
3850 	  for (iterateur kt=v.begin();kt!=itprec;++kt)
3851 	    Equation_translate(*kt,0,currenth);
3852 	  if (y){
3853 	    for (iterateur kt=itprec;kt!=it;++kt)
3854 	      Equation_translate(*kt,0,-y);
3855 	  }
3856 	  itprec=it;
3857 	  currenth=vv.dy;
3858 	  y=vv.y;
3859 	}
3860 	else
3861 #endif
3862 	  {
3863 	    Equation_translate(*it,x,0);
3864 	    vv=Equation_total_size(*it);
3865 	    Equation_vertical_adjust(vv.dy,vv.y,currenth,y);
3866 	  }
3867 	x+=vv.dx;
3868 	if (need_parenthesis(vv.g))
3869 	  x+=lrp;
3870 	++it;
3871 	if (it==itend){
3872 	  for (iterateur kt=v.begin();kt!=itprec;++kt)
3873 	    Equation_translate(*kt,0,currenth+y);
3874 	  h+=currenth;
3875 	  v.push_back(eqwdata(max(x,largeur),h,0,y,a,u,0));
3876 	  //cout << v << endl;
3877 	  return gen(v,_SEQ__VECT);
3878 	}
3879 	x += ls+3;
3880       }
3881     }
3882     // normal printing
3883     x=ls+llp;
3884     for (;;){
3885       eqwdata vv=Equation_total_size(*it);
3886       Equation_translate(*it,x,0);
3887       Equation_vertical_adjust(vv.dy,vv.y,h,y);
3888       x+=vv.dx;
3889       ++it;
3890       if (it==itend){
3891 	x+=lrp;
3892 	v.push_back(eqwdata(x,h,0,y,a,u,0));
3893 	return gen(v,_SEQ__VECT);
3894       }
3895       x+=lc;
3896     }
3897   }
3898 
3899   // windowhsize is used for g of type HIST__VECT (history) right justify answers
3900   // Returns either a eqwdata type object (terminal) or a vector
3901   // (of subtype _EQW__VECT or _HIST__VECT)
Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT)3902   gen Equation_compute_size(const gen & g,const attributs & a,int windowhsize,GIAC_CONTEXT){
3903     /*****************
3904      *   FRACTIONS   *
3905      *****************/
3906     if (g.type==_FRAC){
3907       if (is_integer(g._FRACptr->num) && is_positive(-g._FRACptr->num,contextptr))
3908 	return Equation_compute_size(symbolic(at_neg,fraction(-g._FRACptr->num,g._FRACptr->den)),a,windowhsize,contextptr);
3909       gen v1=Equation_compute_size(g._FRACptr->num,a,windowhsize,contextptr);
3910       eqwdata vv1=Equation_total_size(v1);
3911       gen v2=Equation_compute_size(g._FRACptr->den,a,windowhsize,contextptr);
3912       eqwdata vv2=Equation_total_size(v2);
3913       // Center the fraction
3914       int w1=vv1.dx,w2=vv2.dx;
3915       int w=max(w1,w2)+6;
3916       vecteur v(3);
3917       v[0]=v1; Equation_translate(v[0],(w-w1)/2,11-vv1.y);
3918       v[1]=v2; Equation_translate(v[1],(w-w2)/2,5-vv2.dy-vv2.y);
3919       v[2]=eqwdata(w,a.fontsize/2+vv1.dy+vv2.dy+1,0,(a.fontsize<=14?4:3)-vv2.dy,a,at_division,0);
3920       return gen(v,_SEQ__VECT);
3921     }
3922     /***************
3923      *   VECTORS   *
3924      ***************/
3925     if ( (g.type==_VECT) && !g._VECTptr->empty() ){
3926       vecteur v;
3927       const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
3928       int x=0,y=0,h=a.fontsize;
3929       /***************
3930        *   MATRICE   *
3931        ***************/
3932       bool gmat=ckmatrix(g);
3933       vector<int> V; int p=0;
3934       if (!gmat && is_mod_vecteur(*g._VECTptr,V,p) && p!=0){
3935 	gen gm=makemodquoted(unmod(g),p);
3936 	return Equation_compute_size(gm,a,windowhsize,contextptr);
3937       }
3938       vector< vector<int> > M;
3939       if (gmat && is_mod_matrice(*g._VECTptr,M,p) && p!=0){
3940 	gen gm=makemodquoted(unmod(g),p);
3941 	return Equation_compute_size(gm,a,windowhsize,contextptr);
3942       }
3943       if (gmat && g.subtype!=_SEQ__VECT && g.subtype!=_SET__VECT && g.subtype!=_POLY1__VECT && g._VECTptr->front().subtype!=_SEQ__VECT){
3944 	gen mkvect(at_makevector);
3945 	mkvect.subtype=_SEQ__VECT;
3946 	gen mkmat(at_makevector);
3947 	mkmat.subtype=_MATRIX__VECT;
3948 	int nrows,ncols;
3949 	mdims(*g._VECTptr,nrows,ncols);
3950 	if (ncols){
3951 	  vecteur all_sizes;
3952 	  all_sizes.reserve(nrows);
3953 	  vector<int> row_heights(nrows),row_bases(nrows),col_widths(ncols);
3954 	  // vertical gluing
3955 	  for (int i=0;it!=itend;++it,++i){
3956 	    gen tmpg=*it;
3957 	    tmpg.subtype=_SEQ__VECT;
3958 	    vecteur tmp(Equation_subsizes(tmpg,a,max(windowhsize/ncols-a.fontsize,230),contextptr));
3959 	    int h=a.fontsize,y=0;
3960 	    const_iterateur jt=tmp.begin(),jtend=tmp.end();
3961 	    for (int j=0;jt!=jtend;++jt,++j){
3962 	      eqwdata w(Equation_total_size(*jt));
3963 	      Equation_vertical_adjust(w.dy,w.y,h,y);
3964 	      col_widths[j]=max(col_widths[j],(int)w.dx);
3965 	    }
3966 	    if (i)
3967 	      row_heights[i]=row_heights[i-1]+h+a.fontsize/2;
3968 	    else
3969 	      row_heights[i]=h;
3970 	    row_bases[i]=y;
3971 	    all_sizes.push_back(tmp);
3972 	  }
3973 	  // accumulate col widths
3974 	  col_widths.front() +=(3*a.fontsize)/2;
3975 	  vector<int>::iterator iit=col_widths.begin()+1,iitend=col_widths.end();
3976 	  for (;iit!=iitend;++iit)
3977 	    *iit += *(iit-1)+a.fontsize;
3978 	  // translate each cell
3979 	  it=all_sizes.begin();
3980 	  itend=all_sizes.end();
3981 	  int h,y,prev_h=0;
3982 	  for (int i=0;it!=itend;++it,++i){
3983 	    h=row_heights[i];
3984 	    y=row_bases[i];
3985 	    iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();
3986 	    for (int j=0;jt!=jtend;++jt,++j){
3987 	      eqwdata w(Equation_total_size(*jt));
3988 	      if (j)
3989 		Equation_translate(*jt,col_widths[j-1]-w.x,-h-y);
3990 	      else
3991 		Equation_translate(*jt,-w.x+a.fontsize/2,-h-y);
3992 	    }
3993 	    it->_VECTptr->push_back(eqwdata(col_widths.back(),h-prev_h,0,-h,a,mkvect,0));
3994 	    prev_h=h;
3995 	  }
3996 	  all_sizes.push_back(eqwdata(col_widths.back(),row_heights.back(),0,-row_heights.back(),a,mkmat,-row_heights.back()/2));
3997 	  gen all_sizesg=all_sizes; Equation_translate(all_sizesg,0,row_heights.back()/2); return all_sizesg;
3998 	}
3999       } // end matrices
4000       /*************************
4001        *   SEQUENCES/VECTORS   *
4002        *************************/
4003       // horizontal gluing
4004       if (g.subtype!=_PRINT__VECT) x += a.fontsize/2;
4005       int ncols=itend-it;
4006       //ncols=min(ncols,5);
4007       for (;it!=itend;++it){
4008 	gen cur_size=Equation_compute_size(*it,a,
4009 					   max(windowhsize/ncols-a.fontsize,
4010 #ifdef IPAQ
4011 					       200
4012 #else
4013 					       480
4014 #endif
4015 					       ),contextptr);
4016 	eqwdata tmp=Equation_total_size(cur_size);
4017 	Equation_translate(cur_size,x-tmp.x,0); v.push_back(cur_size);
4018 	x=x+tmp.dx+((g.subtype==_PRINT__VECT)?2:a.fontsize);
4019 	Equation_vertical_adjust(tmp.dy,tmp.y,h,y);
4020       }
4021       gen mkvect(at_makevector);
4022       if (g.subtype==_SEQ__VECT)
4023 	mkvect=at_makesuite;
4024       else
4025 	mkvect.subtype=g.subtype;
4026       v.push_back(eqwdata(x,h,0,y,a,mkvect,0));
4027       return gen(v,_EQW__VECT);
4028     } // end sequences
4029     if (g.type==_MOD){
4030       int x=0;
4031       int h=a.fontsize;
4032       int y=0;
4033       bool py=python_compat(contextptr);
4034       int modsize=int(text_width(a.fontsize,(py?" mod":"%")))+4;
4035       bool paren=is_positive(-*g._MODptr,contextptr);
4036       int llp=int(text_width(a.fontsize,("(")));
4037       int lrp=int(text_width(a.fontsize,(")")));
4038       gen varg1=Equation_compute_size(*g._MODptr,a,windowhsize,contextptr);
4039       if (paren) Equation_translate(varg1,llp,0);
4040       eqwdata vv=Equation_total_size(varg1);
4041       Equation_vertical_adjust(vv.dy,vv.y,h,y);
4042       gen arg2=*(g._MODptr+1);
4043       gen varg2=Equation_compute_size(arg2,a,windowhsize,contextptr);
4044       if (paren)
4045 	Equation_translate(varg2,vv.dx+modsize+lrp,0);
4046       else
4047 	Equation_translate(varg2,vv.dx+modsize,0);
4048       vv=Equation_total_size(varg2);
4049       Equation_vertical_adjust(vv.dy,vv.y,h,y);
4050       vecteur res(makevecteur(varg1,varg2));
4051       res.push_back(eqwdata(vv.dx+vv.x,h,0,y,a,at_normalmod,0));
4052       return gen(res,_SEQ__VECT);
4053     }
4054     if (g.type!=_SYMB){
4055       string s=g.type==_STRNG?*g._STRNGptr:g.print(contextptr);
4056       //if (g==cst_pi) s=char(129);
4057       if (s.size()>2000)
4058 	s=s.substr(0,2000)+"...";
4059       int i=int(text_width(a.fontsize,(s.c_str())));
4060       gen tmp=eqwdata(i,a.fontsize,0,0,a,g);
4061       return tmp;
4062     }
4063     /**********************
4064      *  SYMBOLIC HANDLING *
4065      **********************/
4066     return Equation_compute_symb_size(g,a,windowhsize,contextptr);
4067     // return Equation_compute_symb_size(aplatir_fois_plus(g),a,windowhsize,contextptr);
4068     // aplatir_fois_plus is a problem for Equation_replace_selection
4069     // because it will modify the structure of the data
4070   }
4071 
Equation_draw(const eqwdata & e,int x,int y,int rightx,int lowery,Equation * eq,GIAC_CONTEXT)4072   void Equation_draw(const eqwdata & e,int x,int y,int rightx,int lowery,Equation * eq,GIAC_CONTEXT){
4073     if ( (e.dx+e.x<x) || (e.x>rightx) || (e.y>y) || e.y+e.dy<lowery)
4074       ; // return; // nothing to draw, out of window
4075     gen gg=e.g;
4076     int fontsize=e.eqw_attributs.fontsize;
4077     int text_color=COLOR_BLACK;
4078     int background=COLOR_WHITE;
4079     string s=gg.type==_STRNG?*gg._STRNGptr:gg.print(contextptr);
4080     if (gg.type==_IDNT && !s.empty() && s[0]=='_')
4081       s=s.substr(1,s.size()-1);
4082     // if (gg==cst_pi){      s="p";      s[0]=(unsigned char)129;    }
4083     if (s.size()>2000)
4084       s=s.substr(0,2000)+"...";
4085     // cerr << s.size() << endl;
4086     text_print(fontsize,s.c_str(),eq->x()+e.x-x,eq->y()+y-e.y,text_color,background,e.selected?4:0);
4087     return;
4088   }
4089 
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,int c)4090   inline 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,int c){
4091     drawRectangle(x+delta_i,y+delta_j,w,h,c);
4092     //fl_rectf(x+delta_i,y+delta_j,w,h,c);
4093   }
4094 
Equation_draw(const gen & g,int x,int y,int rightx,int lowery,Equation * equat,GIAC_CONTEXT)4095   void Equation_draw(const gen & g,int x,int y,int rightx,int lowery,Equation * equat,GIAC_CONTEXT){
4096     int eqx=equat->x(),eqy=equat->y();
4097     if (g.type==_EQW){ // terminal
4098       eqwdata & e=*g._EQWptr;
4099       Equation_draw(e,x,y,rightx,lowery,equat,contextptr);
4100     }
4101     if (g.type!=_VECT)
4102       return;
4103     vecteur & v=*g._VECTptr;
4104     if (v.empty())
4105       return;
4106     gen tmp=v.back();
4107     if (tmp.type!=_EQW){
4108       cout << "EQW error:" << v << endl;
4109       return;
4110     }
4111     eqwdata & w=*tmp._EQWptr;
4112     if ( (w.dx+w.x-x<0) || (w.x>rightx) || (w.y>y) || (w.y+w.dy<lowery) )
4113       ; // return; // nothing to draw, out of window
4114     /*******************
4115      * draw the vector *
4116      *******************/
4117     // v is the vector, w the master operator eqwdata
4118     gen oper=w.g;
4119     bool selected=w.selected ;
4120     int fontsize=w.eqw_attributs.fontsize;
4121     int background=w.eqw_attributs.background;
4122     int text_color=w.eqw_attributs.text_color;
4123     int mode=selected?4:0;
4124     int draw_line_color=selected?background:text_color;
4125     int x0=w.x;
4126     int y0=w.y; // lower coordinate of the master vector
4127     int y1=y0+w.dy; // upper coordinate of the master vector
4128     if (selected)
4129       drawRectangle(eqx+w.x-x,eqy+y-w.y-w.dy+1,w.dx,w.dy+1,text_color);
4130     // draw arguments of v
4131     const_iterateur it=v.begin(),itend=v.end()-1;
4132     if (oper==at_expr && v.size()==3){
4133       Equation_draw(*it,x,y,rightx,lowery,equat,contextptr);
4134       return;
4135     }
4136     for (;it!=itend;++it)
4137       Equation_draw(*it,x,y,rightx,lowery,equat,contextptr);
4138     if (oper==at_multistring)
4139       return;
4140     string s;
4141     if (oper.type==_FUNC){
4142       // catch here special cases user function, vect/matr, ^, int, sqrt, etc.
4143       unary_function_ptr & u=*oper._FUNCptr;
4144       if (u==at_at){ // draw brackets around 2nd arg
4145 	gen arg2=v[1]; // 2nd arg of at_of, i.e. what's inside the parenth.
4146 	eqwdata varg2=Equation_total_size(arg2);
4147 	x0=varg2.x;
4148 	y0=varg2.y;
4149 	y1=y0+varg2.dy;
4150 	fontsize=varg2.eqw_attributs.fontsize;
4151 	if (x0<rightx)
4152 	  text_print(fontsize,"[",eqx+x0-x-int(text_width(fontsize,("["))),eqy+y-varg2.baseline,text_color,background,mode);
4153 	x0 += varg2.dx ;
4154 	if (x0<rightx)
4155 	  text_print(fontsize,"]",eqx+x0-x,eqy+y-varg2.baseline,text_color,background,mode);
4156 	return;
4157       }
4158       if (u==at_of){ // do we need to draw some parenthesis?
4159 	gen arg2=v[1]; // 2nd arg of at_of, i.e. what's inside the parenth.
4160 	if (arg2.type!=_VECT || arg2._VECTptr->back().type !=_EQW || arg2._VECTptr->back()._EQWptr->g!=at_makesuite){ // Yes (if not _EQW it's a sequence with parent)
4161 	  eqwdata varg2=Equation_total_size(arg2);
4162 	  x0=varg2.x;
4163 	  y0=varg2.y;
4164 	  y1=y0+varg2.dy;
4165 	  fontsize=varg2.eqw_attributs.fontsize;
4166 	  int pfontsize=max(fontsize,(fontsize+(varg2.baseline-varg2.y))/2);
4167 	  if (x0<rightx)
4168 	    text_print(pfontsize,"(",eqx+x0-x-int(text_width(fontsize,("("))),eqy+y-varg2.baseline,text_color,background,mode);
4169 	  x0 += varg2.dx ;
4170 	  if (x0<rightx)
4171 	    text_print(pfontsize,")",eqx+x0-x,eqy+y-varg2.baseline,text_color,background,mode);
4172 	}
4173 	return;
4174       }
4175       if (u==at_makesuite){
4176 	bool paren=v.size()!=2; // Sequences with 1 arg don't show parenthesis
4177 	int pfontsize=max(fontsize,(fontsize+(w.baseline-w.y))/2);
4178 	if (paren && x0<rightx)
4179 	  text_print(pfontsize,"(",eqx+x0-x-int(text_width(fontsize,("(")))/2,eqy+y-w.baseline,text_color,background,mode);
4180 	x0 += w.dx;
4181 	if (paren && x0<rightx)
4182 	  text_print(pfontsize,")",eqx+x0-x-int(text_width(fontsize,("(")))/2,eqy+y-w.baseline,text_color,background,mode);
4183 	// print commas between args
4184 	it=v.begin(),itend=v.end()-2;
4185 	for (;it!=itend;++it){
4186 	  eqwdata varg2=Equation_total_size(*it);
4187 	  fontsize=varg2.eqw_attributs.fontsize;
4188 	  if (varg2.x+varg2.dx<rightx)
4189 	    text_print(fontsize,",",eqx+varg2.x+varg2.dx-x+1,eqy+y-varg2.baseline,text_color,background,mode);
4190 	}
4191 	return;
4192       }
4193       if (u==at_makevector){ // draw [] delimiters for vector/matrices
4194 	if (oper.subtype!=_SEQ__VECT && oper.subtype!=_PRINT__VECT){
4195 	  int decal=1;
4196 	  switch (oper.subtype){
4197 	  case _MATRIX__VECT: decal=2; break;
4198 	  case _SET__VECT: decal=4; break;
4199 	  case _POLY1__VECT: decal=6; break;
4200 	  }
4201 	  if (eqx+x0-x+1>=0){
4202 	    draw_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+1,eqy+y-y1+1,draw_line_color);
4203 	    draw_line(eqx+x0-x+decal,eqy+y-y0+1,eqx+x0-x+decal,eqy+y-y1+1,draw_line_color);
4204 	    draw_line(eqx+x0-x+1,eqy+y-y0+1,eqx+x0-x+fontsize/4,eqy+y-y0+1,draw_line_color);
4205 	    draw_line(eqx+x0-x+1,eqy+y-y1+1,eqx+x0-x+fontsize/4,eqy+y-y1+1,draw_line_color);
4206 	  }
4207 	  x0 += w.dx ;
4208 	  if (eqx+x0-x-1<LCD_WIDTH_PX){
4209 	    draw_line(eqx+x0-x-1,eqy+y-y0+1,eqx+x0-x-1,eqy+y-y1+1,draw_line_color);
4210 	    draw_line(eqx+x0-x-decal,eqy+y-y0+1,eqx+x0-x-decal,eqy+y-y1+1,draw_line_color);
4211 	    draw_line(eqx+x0-x-1,eqy+y-y0+1,eqx+x0-x-fontsize/4,eqy+y-y0+1,draw_line_color);
4212 	    draw_line(eqx+x0-x-1,eqy+y-y1+1,eqx+x0-x-fontsize/4,eqy+y-y1+1,draw_line_color);
4213 	  }
4214 	} // end if oper.subtype!=SEQ__VECT
4215 	if (oper.subtype!=_MATRIX__VECT && oper.subtype!=_PRINT__VECT){
4216 	  // print commas between args
4217 	  it=v.begin(),itend=v.end()-2;
4218 	  for (;it!=itend;++it){
4219 	    eqwdata varg2=Equation_total_size(*it);
4220 	    fontsize=varg2.eqw_attributs.fontsize;
4221 	    if (varg2.x+varg2.dx<rightx)
4222 	      text_print(fontsize,",",eqx+varg2.x+varg2.dx-x+1,eqy+y-varg2.baseline,text_color,background,mode);
4223 	  }
4224 	}
4225 	return;
4226       }
4227       int lpsize=int(text_width(fontsize,("(")));
4228       int rpsize=int(text_width(fontsize,(")")));
4229       eqwdata tmp=Equation_total_size(v.front()); // tmp= 1st arg eqwdata
4230       if (u==at_sto)
4231 	tmp=Equation_total_size(v[1]);
4232       x0=w.x-x;
4233       y0=y-w.baseline;
4234       if (u==at_pow){
4235 	if (!need_parenthesis(tmp.g)&& tmp.g!=at_pow && tmp.g!=at_prod && tmp.g!=at_division)
4236 	  return;
4237 	if (tmp.g==at_pow){
4238 	  fontsize=tmp.eqw_attributs.fontsize+2;
4239 	}
4240 	if (tmp.x-lpsize<rightx)
4241 	  text_print(fontsize,"(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,text_color,background,mode);
4242 	if (tmp.x+tmp.dx<rightx)
4243 	  text_print(fontsize,")",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,text_color,background,mode);
4244 	return;
4245       }
4246       if (u==at_program){
4247 	if (tmp.x+tmp.dx<rightx)
4248 	  text_print(fontsize,"->",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,text_color,background,mode);
4249 	return;
4250       }
4251 #if 1
4252       if (u==at_sum){
4253 	if (x0<rightx){
4254 	  draw_line(eqx+x0,eqy+y0,eqx+x0+(2*fontsize)/3,eqy+y0,draw_line_color);
4255 	  draw_line(eqx+x0,eqy+y0-fontsize,eqx+x0+(2*fontsize)/3,eqy+y0-fontsize,draw_line_color);
4256 	  draw_line(eqx+x0,eqy+y0,eqx+x0+fontsize/2,eqy+y0-fontsize/2,draw_line_color);
4257 	  draw_line(eqx+x0+fontsize/2,eqy+y0-fontsize/2,eqx+x0,eqy+y0-fontsize,draw_line_color);
4258 	  if (v.size()>2){ // draw the =
4259 	    eqwdata ptmp=Equation_total_size(v[1]);
4260 	    if (ptmp.x+ptmp.dx<rightx)
4261 	      text_print(fontsize,"=",eqx+ptmp.x+ptmp.dx-x-2,eqy+y-ptmp.baseline,text_color,background,mode);
4262 	  }
4263 	}
4264 	return;
4265       }
4266 #endif
4267       if (u==at_abs){
4268 	y0 =1+y-w.y;
4269 	int h=w.dy;
4270 	if (x0<rightx){
4271 	  draw_line(eqx+x0+2,eqy+y0-1,eqx+x0+2,eqy+y0-h+3,draw_line_color);
4272 	  draw_line(eqx+x0+1,eqy+y0-1,eqx+x0+1,eqy+y0-h+3,draw_line_color);
4273 	  draw_line(eqx+x0+w.dx-1,eqy+y0-1,eqx+x0+w.dx-1,eqy+y0-h+3,draw_line_color);
4274 	  draw_line(eqx+x0+w.dx,eqy+y0-1,eqx+x0+w.dx,eqy+y0-h+3,draw_line_color);
4275 	}
4276 	return;
4277       }
4278       if (u==at_sqrt){
4279 	y0 =1+y-w.y;
4280 	int h=w.dy;
4281 	if (x0<rightx){
4282 	  draw_line(eqx+x0+2,eqy+y0-h/2,eqx+x0+fontsize/2,eqy+y0-1,draw_line_color);
4283 	  draw_line(eqx+x0+fontsize/2,eqy+y0-1,eqx+x0+fontsize,eqy+y0-h+3,draw_line_color);
4284 	  draw_line(eqx+x0+fontsize,eqy+y0-h+3,eqx+x0+w.dx-1,eqy+y0-h+3,draw_line_color);
4285 	  ++y0;
4286 	  draw_line(eqx+x0+2,eqy+y0-h/2,eqx+x0+fontsize/2,eqy+y0-1,draw_line_color);
4287 	  draw_line(eqx+x0+fontsize/2,eqy+y0-1,eqx+x0+fontsize,eqy+y0-h+3,draw_line_color);
4288 	  draw_line(eqx+x0+fontsize,eqy+y0-h+3,eqx+x0+w.dx-1,eqy+y0-h+3,draw_line_color);
4289 	}
4290 	return;
4291       }
4292       if (u==at_factorial){
4293 	text_print(fontsize,"!",eqx+w.x+w.dx-4-x,eqy+y-w.baseline,text_color,background,mode);
4294 	if (!need_parenthesis(tmp.g)
4295 	    && tmp.g!=at_pow && tmp.g!=at_prod && tmp.g!=at_division
4296 	    )
4297 	  return;
4298 	if (tmp.x-lpsize<rightx)
4299 	  text_print(fontsize,"(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,text_color,background,mode);
4300 	if (tmp.x+tmp.dx<rightx)
4301 	  text_print(fontsize,")",eqx+tmp.x+tmp.dx-x,eqy+y-tmp.baseline,text_color,background,mode);
4302 	return;
4303       }
4304 #if 1
4305       if (u==at_integrate){
4306 	x0+=2;
4307 	y0+=fontsize/2;
4308 	if (x0<rightx){
4309 	  fl_arc(eqx+x0,eqy+y0,fontsize/3,fontsize/3,180,360,draw_line_color);
4310 	  draw_line(eqx+x0+fontsize/3,eqy+y0,eqx+x0+fontsize/3,eqy+y0-2*fontsize+4,draw_line_color);
4311 	  fl_arc(eqx+x0+fontsize/3,eqy+y0-2*fontsize+3,fontsize/3,fontsize/3,0,180,draw_line_color);
4312 	}
4313 	if (v.size()!=2){ // if arg has size > 1 draw the d
4314 	  eqwdata ptmp=Equation_total_size(v[1]);
4315 	  if (ptmp.x<rightx)
4316 	    text_print(fontsize," d",eqx+ptmp.x-x-int(text_width(fontsize,(" d"))),eqy+y-ptmp.baseline,text_color,background,mode);
4317 	}
4318 	else {
4319 	  eqwdata ptmp=Equation_total_size(v[0]);
4320 	  if (ptmp.x+ptmp.dx<rightx)
4321 	    text_print(fontsize," dx",eqx+ptmp.x+ptmp.dx-x,eqy+y-ptmp.baseline,text_color,background,mode);
4322 	}
4323 	return;
4324       }
4325 #endif
4326       if (u==at_division){
4327 	if (x0<rightx){
4328 	  int yy=eqy+y0-8;
4329 	  draw_line(eqx+x0+2,yy,eqx+x0+w.dx-2,yy,draw_line_color);
4330 	  ++yy;
4331 	  draw_line(eqx+x0+2,yy,eqx+x0+w.dx-2,yy,draw_line_color);
4332 	}
4333 	return;
4334       }
4335 #if 1
4336       if (u==at_limit && v.size()>=4){
4337 	if (x0<rightx)
4338 	  text_print(fontsize,"lim",eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode);
4339 	gen arg2=v[1]; // 2nd arg of limit, i.e. the variable
4340 	if (arg2.type==_EQW){
4341 	  eqwdata & varg2=*arg2._EQWptr;
4342 	  if (varg2.x+varg2.dx+2<rightx)
4343 	    text_print(fontsize,"\x1e",eqx+varg2.x+varg2.dx+2-x,eqy+y-varg2.y,text_color,background,mode);
4344 	}
4345 	if (v.size()>=5){
4346 	  arg2=v[2]; // 3rd arg of lim, the point, draw a comma after if dir.
4347 	  if (arg2.type==_EQW){
4348 	    eqwdata & varg2=*arg2._EQWptr;
4349 	    if (varg2.x+varg2.dx<rightx)
4350 	      text_print(fontsize,",",eqx+varg2.x+varg2.dx-x,eqy+y-varg2.baseline,text_color,background,mode);
4351 	  }
4352 	}
4353 	return;
4354       } // limit
4355 #endif
4356       bool parenthesis=true;
4357       string opstring(",");
4358       if (u.ptr()->printsommet==&printsommetasoperator || binary_op(u) ){
4359 	if (u==at_normalmod && python_compat(contextptr))
4360 	  opstring=" mod";
4361 	else
4362 	  opstring=u.ptr()->s;
4363       }
4364       else {
4365 	if (u==at_sto)
4366 	  opstring=":=";
4367 	parenthesis=false;
4368       }
4369       // int yy=y0; // y0 is the lower coordinate of the whole eqwdata
4370       // int opsize=int(text_width(fontsize,(opstring.c_str())))+3;
4371       it=v.begin();
4372       itend=v.end()-1;
4373       // Reminder: here tmp is the 1st arg eqwdata, w the whole eqwdata
4374       if ( (itend-it==1) && ( (u==at_neg)
4375 			      || (u==at_plus) // uncommented for +infinity
4376 			      ) ){
4377 	if ( (u==at_neg &&need_parenthesis(tmp.g) && tmp.g!=at_prod)){
4378 	  if (tmp.x-lpsize<rightx)
4379 	    text_print(fontsize,"(",eqx+tmp.x-x-lpsize,eqy+y-tmp.baseline,text_color,background,mode);
4380 	  if (tmp.x+tmp.dx<rightx)
4381 	    text_print(fontsize,")",eqx+tmp.x-x+tmp.dx,eqy+y-tmp.baseline,text_color,background,mode);
4382 	}
4383 	if (w.x<rightx){
4384 	  text_print(fontsize,u.ptr()->s,eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode);
4385 	}
4386 	return;
4387       }
4388       // write first open parenthesis
4389       if (u==at_plus && tmp.g!=at_equal)
4390 	parenthesis=false;
4391       else {
4392 	if (parenthesis && need_parenthesis(tmp.g)){
4393 	  if (w.x<rightx){
4394 	    int pfontsize=max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2);
4395 	    text_print(pfontsize,"(",eqx+w.x-x,eqy+y-tmp.baseline,text_color,background,mode);
4396 	  }
4397 	}
4398       }
4399       for (;;){
4400 	// write close parenthesis at end
4401 	int xx=tmp.dx+tmp.x-x;
4402 	if (parenthesis && need_parenthesis(tmp.g)){
4403 	  if (xx<rightx){
4404 	    int pfontsize=min(max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2),fontsize*2);
4405 	    int deltapary=(2*(pfontsize-fontsize))/3;
4406 	    text_print(pfontsize,")",eqx+xx,eqy+y-tmp.baseline+deltapary,text_color,background,mode);
4407 	  }
4408 	  xx +=rpsize;
4409 	}
4410 	++it;
4411 	if (it==itend){
4412 	  if (u.ptr()->printsommet==&printsommetasoperator || u==at_sto || binary_op(u))
4413 	    return;
4414 	  else
4415 	    break;
4416 	}
4417 	// write operator
4418 	if (u==at_prod){
4419 	  // text_print(fontsize,".",eqx+xx+3,eqy+y-tmp.baseline-fontsize/3);
4420 	  text_print(fontsize,opstring.c_str(),eqx+xx+1,eqy+y-tmp.baseline,text_color,background,mode);
4421 	}
4422 	else {
4423 	  gen tmpgen;
4424 	  if (u==at_plus && (
4425 			     (it->type==_VECT && it->_VECTptr->back().type==_EQW && it->_VECTptr->back()._EQWptr->g==at_neg)
4426 			     ||
4427 			     ( it->type==_EQW && (is_integer(it->_EQWptr->g) || it->_EQWptr->g.type==_DOUBLE_) && is_strictly_positive(-it->_EQWptr->g,contextptr) )
4428 			      )
4429 	      )
4430 	    ;
4431 	  else {
4432 	    if (xx+1<rightx)
4433 	      // fl_draw(opstring.c_str(),xx+1,y-tmp.y-tmp.dy/2+fontsize/2);
4434 	      text_print(fontsize,opstring.c_str(),eqx+xx+1,eqy+y-tmp.baseline,text_color,background,mode);
4435 	  }
4436 	}
4437 	// write right parent, update tmp
4438 	tmp=Equation_total_size(*it);
4439 	if (parenthesis && (need_parenthesis(tmp.g)) ){
4440 	  if (tmp.x-lpsize<rightx){
4441 	    int pfontsize=min(max(fontsize,(fontsize+(tmp.baseline-tmp.y))/2),fontsize*2);
4442 	    int deltapary=(2*(pfontsize-fontsize))/3;
4443 	    text_print(pfontsize,"(",eqx+tmp.x-pfontsize*lpsize/fontsize-x,eqy+y-tmp.baseline+deltapary,text_color,background,mode);
4444 	  }
4445 	}
4446       } // end for (;;)
4447       if (w.x<rightx){
4448 	s = u.ptr()->s;
4449 	s += '(';
4450 	text_print(fontsize,s.c_str(),eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode);
4451       }
4452       if (w.x+w.dx-rpsize<rightx)
4453 	text_print(fontsize,")",eqx+w.x+w.dx-x-rpsize+2,eqy+y-w.baseline,text_color,background,mode);
4454       return;
4455     }
4456     s=oper.print(contextptr);
4457     if (w.x<rightx){
4458       text_print(fontsize,s.c_str(),eqx+w.x-x,eqy+y-w.baseline,text_color,background,mode);
4459     }
4460   }
4461 
Equation(int x_,int y_,const gen & g,const giac::context * cptr)4462   Equation::Equation(int x_, int y_, const gen & g,const giac::context * cptr){
4463     _x=x_;
4464     _y=y_;
4465     attr=attributs(18,COLOR_WHITE,COLOR_BLACK);
4466     contextptr=cptr;
4467     if (taille(g,max_prettyprint_equation)<max_prettyprint_equation)
4468       data=Equation_compute_size(g,attr,LCD_WIDTH_PX,contextptr);
4469     else
4470       data=Equation_compute_size(string2gen("Object_too_large",false),attr,LCD_WIDTH_PX,contextptr);
4471     undodata=Equation_copy(data);
4472   }
4473 
replace_selection(Equation & eq,const gen & tmp,gen * gsel,const vector<int> * gotoptr,GIAC_CONTEXT)4474   void replace_selection(Equation & eq,const gen & tmp,gen * gsel,const vector<int> * gotoptr,GIAC_CONTEXT){
4475     int xleft,ytop,xright,ybottom,gselpos; gen *gselparent;
4476     vector<int> goto_sel;
4477     eq.undodata=Equation_copy(eq.data);
4478     if (gotoptr==0){
4479       if (xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gsel)
4480 	gotoptr=&goto_sel;
4481       else
4482 	return;
4483     }
4484     *gsel=xcas::Equation_compute_size(tmp,eq.attr,LCD_WIDTH_PX,contextptr);
4485     gen value;
4486     xcas::do_select(eq.data,true,value);
4487     if (value.type==_EQW)
4488       eq.data=xcas::Equation_compute_size(value._EQWptr->g,eq.attr,LCD_WIDTH_PX,contextptr);
4489     //cout << "new value " << value << " " << eq.data << " " << *gotoptr << endl;
4490     xcas::Equation_select(eq.data,false);
4491     gen * gptr=&eq.data;
4492     for (int i=gotoptr->size()-1;i>=0;--i){
4493       int pos=(*gotoptr)[i];
4494       if (gptr->type==_VECT &&gptr->_VECTptr->size()>pos)
4495 	gptr=&(*gptr->_VECTptr)[pos];
4496     }
4497     xcas::Equation_select(*gptr,true);
4498     //cout << "new sel " << *gptr << endl;
4499   }
4500 
display(Equation & eq,int x,int y,GIAC_CONTEXT)4501   void display(Equation & eq,int x,int y,GIAC_CONTEXT){
4502     // Equation_draw(eq.data,x,y,LCD_WIDTH_PX,0,&eq,contextptr);
4503     int xleft,ytop,xright,ybottom,gselpos; gen * gsel,*gselparent;
4504     eqwdata eqdata=Equation_total_size(eq.data);
4505     if ( (eqdata.dx>LCD_WIDTH_PX || eqdata.dy>LCD_HEIGHT_PX-STATUS_AREA_PX) && Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos)){
4506       if (x<xleft){
4507 	if (x+LCD_WIDTH_PX<xright)
4508 	  x=giacmin(xleft,xright-LCD_WIDTH_PX);
4509       }
4510       if (x>=xleft && x+LCD_WIDTH_PX>=xright){
4511 	if (xright-x<LCD_WIDTH_PX)
4512 	  x=giacmax(xright-LCD_WIDTH_PX,0);
4513       }
4514 #if 0
4515       cout << "avant " << y << " " << ytop << " " << ybottom << endl;
4516       if (y<ytop){
4517 	if (y+LCD_HEIGHT_PX<ybottom)
4518 	  y=giacmin(ytop,ybottom-LCD_HEIGHT_PX);
4519       }
4520       if (y>=ytop && y+LCD_HEIGHT_PX>=ybottom){
4521 	if (ybottom-y<LCD_HEIGHT_PX)
4522 	  y=giacmax(ybottom-LCD_HEIGHT_PX,0);
4523       }
4524       cout << "apres " << y << " " << ytop << " " << ybottom << endl;
4525 #endif
4526     }
4527     int save_ymin_clip=clip_ymin;
4528     clip_ymin=STATUS_AREA_PX;
4529     Equation_draw(eq.data,x,y,RAND_MAX,0,&eq,contextptr);
4530     clip_ymin=save_ymin_clip;
4531   }
4532 
4533   /* ******************* *
4534    *      GRAPH          *
4535    * ******************* *
4536    */
4537 #if 1
4538 
find_tick(double dx)4539   double find_tick(double dx){
4540     double d=std::pow(10.0,std::floor(std::log10(absdouble(dx))));
4541     if (dx<2*d)
4542       d=d/5;
4543     else {
4544       if (dx<5*d)
4545 	d=d/2;
4546     }
4547     return d;
4548   }
4549 
Graph2d(const giac::gen & g_,const giac::context * cptr)4550   Graph2d::Graph2d(const giac::gen & g_,const giac::context * cptr):window_xmin(gnuplot_xmin),window_xmax(gnuplot_xmax),window_ymin(gnuplot_ymin),window_ymax(gnuplot_ymax),g(g_),display_mode(0x45),show_axes(1),show_names(1),labelsize(16),contextptr(cptr) {
4551     update();
4552     autoscale();
4553   }
4554 
zoomx(double d,bool round)4555   void Graph2d::zoomx(double d,bool round){
4556     double x_center=(window_xmin+window_xmax)/2;
4557     double dx=(window_xmax-window_xmin);
4558     if (dx==0)
4559       dx=gnuplot_xmax-gnuplot_xmin;
4560     dx *= d/2;
4561     x_tick = find_tick(dx);
4562     window_xmin = x_center - dx;
4563     if (round)
4564       window_xmin=int( window_xmin/x_tick -1)*x_tick;
4565     window_xmax = x_center + dx;
4566     if (round)
4567       window_xmax=int( window_xmax/x_tick +1)*x_tick;
4568     update();
4569   }
4570 
zoomy(double d,bool round)4571   void Graph2d::zoomy(double d,bool round){
4572     double y_center=(window_ymin+window_ymax)/2;
4573     double dy=(window_ymax-window_ymin);
4574     if (dy==0)
4575       dy=gnuplot_ymax-gnuplot_ymin;
4576     dy *= d/2;
4577     y_tick = find_tick(dy);
4578     window_ymin = y_center - dy;
4579     if (round)
4580       window_ymin=int( window_ymin/y_tick -1)*y_tick;
4581     window_ymax = y_center + dy;
4582     if (round)
4583       window_ymax=int( window_ymax/y_tick +1)*y_tick;
4584     update();
4585   }
4586 
zoom(double d)4587   void Graph2d::zoom(double d){
4588     zoomx(d);
4589     zoomy(d);
4590   }
4591 
autoscale(bool fullview)4592   void Graph2d::autoscale(bool fullview){
4593     // Find the largest and lowest x/y/z in objects (except lines/plans)
4594     vector<double> vx,vy,vz;
4595     int s;
4596     bool ortho=autoscaleg(g,vx,vy,vz,contextptr);
4597     autoscaleminmax(vx,window_xmin,window_xmax,fullview);
4598     zoomx(1.0);
4599     autoscaleminmax(vy,window_ymin,window_ymax,fullview);
4600     zoomy(1.0);
4601     if (window_xmax-window_xmin<1e-100){
4602       window_xmax=gnuplot_xmax;
4603       window_xmin=gnuplot_xmin;
4604     }
4605     if (window_ymax-window_ymin<1e-100){
4606       window_ymax=gnuplot_ymax;
4607       window_ymin=gnuplot_ymin;
4608     }
4609     bool do_ortho=ortho;
4610     if (!do_ortho){
4611       double w=LCD_WIDTH_PX;
4612       double h=LCD_HEIGHT_PX-STATUS_AREA_PX;
4613       double window_w=window_xmax-window_xmin,window_h=window_ymax-window_ymin;
4614       double tst=h/w*window_w/window_h;
4615       if (tst>0.7 && tst<1.4)
4616 	do_ortho=true;
4617     }
4618     if (do_ortho )
4619       orthonormalize();
4620     y_tick=find_tick(window_ymax-window_ymin);
4621     update();
4622   }
4623 
orthonormalize()4624   void Graph2d::orthonormalize(){
4625     // Center of the directions, orthonormalize
4626     double w=LCD_WIDTH_PX;
4627     double h=LCD_HEIGHT_PX-STATUS_AREA_PX;
4628     double window_w=window_xmax-window_xmin,window_h=window_ymax-window_ymin;
4629     double window_hsize=h/w*window_w;
4630     if (window_h > window_hsize*1.01){ // enlarge horizontally
4631       double window_xcenter=(window_xmin+window_xmax)/2;
4632       double window_wsize=w/h*window_h;
4633       window_xmin=window_xcenter-window_wsize/2;
4634       window_xmax=window_xcenter+window_wsize/2;
4635     }
4636     if (window_h < window_hsize*0.99) { // enlarge vertically
4637       double window_ycenter=(window_ymin+window_ymax)/2;
4638       window_ymin=window_ycenter-window_hsize/2;
4639       window_ymax=window_ycenter+window_hsize/2;
4640     }
4641     x_tick=find_tick(window_xmax-window_xmin);
4642     y_tick=find_tick(window_ymax-window_ymin);
4643     update();
4644   }
4645 
update()4646   void Graph2d::update(){
4647     x_scale=LCD_WIDTH_PX/(window_xmax-window_xmin);
4648     y_scale=(LCD_HEIGHT_PX-STATUS_AREA_PX)/(window_ymax-window_ymin);
4649   }
4650 
findij(const gen & e0,double x_scale,double y_scale,double & i0,double & j0,GIAC_CONTEXT) const4651   bool Graph2d::findij(const gen & e0,double x_scale,double y_scale,double & i0,double & j0,GIAC_CONTEXT) const {
4652     gen e,f0,f1;
4653     evalfdouble2reim(e0,e,f0,f1,contextptr);
4654     if ((f0.type==_DOUBLE_) && (f1.type==_DOUBLE_)){
4655       if (display_mode & 0x400){
4656 	if (f0._DOUBLE_val<=0)
4657 	  return false;
4658 	f0=std::log10(f0._DOUBLE_val);
4659       }
4660       i0=(f0._DOUBLE_val-window_xmin)*x_scale;
4661       if (display_mode & 0x800){
4662 	if (f1._DOUBLE_val<=0)
4663 	  return false;
4664 	f1=std::log10(f1._DOUBLE_val);
4665       }
4666       j0=(window_ymax-f1._DOUBLE_val)*y_scale;
4667       return true;
4668     }
4669     // cerr << "Invalid drawing data" << endl;
4670     return false;
4671   }
4672 
swapint(int & i0,int & i1)4673   inline void swapint(int & i0,int & i1){
4674     int tmp=i0;
4675     i0=i1;
4676     i1=tmp;
4677   }
4678 
check_fl_draw(int fontsize,const char * ch,int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j,int c)4679   void check_fl_draw(int fontsize,const char * ch,int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j,int c){
4680     /* int n=fl_size();
4681        if (j0>=jmin-n && j0<=jmin+dj+n) */
4682     // cerr << i0 << " " << j0 << endl;
4683     if (strlen(ch)>200)
4684       text_print(fontsize,"String too long",i0+delta_i,j0+delta_j,c);
4685     else
4686       text_print(fontsize,ch,i0+delta_i,j0+delta_j,c);
4687   }
4688 
check_fl_point(int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j,int c)4689   inline void check_fl_point(int i0,int j0,int imin,int jmin,int di,int dj,int delta_i,int delta_j,int c){
4690     /* if (i0>=imin && i0<=imin+di && j0>=jmin && j0<=jmin+dj) */
4691     os_set_pixel(i0+delta_i,j0+delta_j,c);
4692   }
4693 
fl_line(int x0,int y0,int x1,int y1,int c)4694   inline void fl_line(int x0,int y0,int x1,int y1,int c){
4695     draw_line(x0,y0,x1,y1,c);
4696   }
4697 
fl_polygon(int x0,int y0,int x1,int y1,int x2,int y2,int c)4698   inline void fl_polygon(int x0,int y0,int x1,int y1,int x2,int y2,int c){
4699     draw_line(x0,y0,x1,y1,c);
4700     draw_line(x1,y1,x2,y2,c);
4701   }
4702 
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,int c)4703   inline 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,int c){
4704     fl_line(i0+delta_i,j0+delta_j,i1+delta_i,j1+delta_j,c);
4705   }
4706 
4707   int logplot_points=20;
4708 
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,int c)4709   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,int c){
4710     if (!logx && !logy){
4711       fl_line(round(i0+deltax),round(j0+deltay),round(i1+deltax),round(j1+deltay),c);
4712       return;
4713     }
4714   }
4715 
find_dxdy(const string & legendes,int labelpos,int labelsize,int & dx,int & dy)4716   void find_dxdy(const string & legendes,int labelpos,int labelsize,int & dx,int & dy){
4717     int l=text_width(labelsize,legendes.c_str());
4718     dx=3;
4719     dy=1;
4720     switch (labelpos){
4721     case 1:
4722       dx=-l-3;
4723       break;
4724     case 2:
4725       dx=-l-3;
4726       dy=labelsize-2;
4727       break;
4728     case 3:
4729       dy=labelsize-2;
4730       break;
4731     }
4732     //dy += labelsize;
4733   }
4734 
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,int c,GIAC_CONTEXT)4735   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,int c,GIAC_CONTEXT){
4736     if (f.empty() ||!iptr->show_names )
4737       return;
4738     string legendes;
4739     if (f[0].is_symb_of_sommet(at_curve)){
4740       gen & f0=f[0]._SYMBptr->feuille;
4741       if (f0.type==_VECT && !f0._VECTptr->empty()){
4742 	gen & f1 = f0._VECTptr->front();
4743 	if (f1.type==_VECT && f1._VECTptr->size()>4 && (!is_zero((*f1._VECTptr)[4]) || (iptr->show_names & 2)) ){
4744 	  gen legende=f1._VECTptr->front();
4745 	  gen var=(*f1._VECTptr)[1];
4746 	  gen r=re(legende,contextptr),i=im(legende,contextptr),a,b;
4747 	  if (var.type==_IDNT && is_linear_wrt(r,*var._IDNTptr,a,b,contextptr)){
4748 	    i=subst(i,var,(var-b)/a,false,contextptr);
4749 	    legendes=i.print(contextptr);
4750 	  }
4751 	  else
4752 	    legendes=r.print(contextptr)+","+i.print(contextptr);
4753 	  if (legendes.size()>18){
4754 	    if (legendes.size()>30)
4755 	      legendes="";
4756 	    else
4757 	      legendes=legendes.substr(0,16)+"...";
4758 	  }
4759 	}
4760       }
4761     }
4762     if (f.size()>2)
4763       legendes=gen2string(f[2])+(legendes.empty()?"":":")+legendes;
4764     if (legendes.empty())
4765       return;
4766     int fontsize=iptr->labelsize;
4767     int dx=3,dy=1;
4768     find_dxdy(legendes,labelpos,fontsize,dx,dy);
4769     check_fl_draw(fontsize,legendes.c_str(),i0+dx,j0+dy,clip_x,clip_y,clip_w,clip_h,deltax,deltay,c);
4770   }
4771 
petite_fleche(double i1,double j1,double dx,double dy,int deltax,int deltay,int width,int c)4772   void petite_fleche(double i1,double j1,double dx,double dy,int deltax,int deltay,int width,int c){
4773     double dxy=std::sqrt(dx*dx+dy*dy);
4774     if (dxy){
4775       dxy/=max(2,min(5,int(dxy/10)))+width;
4776       dx/=dxy;
4777       dy/=dxy;
4778       double dxp=-dy,dyp=dx; // perpendicular
4779       dx*=std::sqrt(3.0);
4780       dy*=sqrt(3.0);
4781       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,c);
4782     }
4783   }
4784 
fltk_point(int deltax,int deltay,int i0,int j0,int epaisseur_point,int type_point,int c)4785   void fltk_point(int deltax,int deltay,int i0,int j0,int epaisseur_point,int type_point,int c){
4786     switch (type_point){
4787     case 1: // losange
4788       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0-epaisseur_point,c);
4789       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0,c);
4790       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0+epaisseur_point,c);
4791       fl_line(deltax+i0,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0,c);
4792       break;
4793     case 2: // croix verticale
4794       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0,deltay+j0+epaisseur_point,c);
4795       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0,c);
4796       break;
4797     case 3: // carre
4798       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0-epaisseur_point,deltay+j0+epaisseur_point,c);
4799       fl_line(deltax+i0+epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point,c);
4800       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0-epaisseur_point,c);
4801       fl_line(deltax+i0-epaisseur_point,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point,c);
4802       break;
4803     case 5: // triangle
4804       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0,deltay+j0-epaisseur_point,c);
4805       fl_line(deltax+i0,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0,c);
4806       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0,c);
4807       break;
4808     case 7: // point
4809       if (epaisseur_point>2)
4810 	fl_arc(deltax+i0-(epaisseur_point-1),deltay+j0-(epaisseur_point-1),2*(epaisseur_point-1),2*(epaisseur_point-1),0,360,c);
4811       else
4812 	fl_line(deltax+i0,deltay+j0,deltax+i0+1,deltay+j0,c);
4813       break;
4814     case 6: // etoile
4815       fl_line(deltax+i0-epaisseur_point,deltay+j0,deltax+i0+epaisseur_point,deltay+j0,c);
4816       // no break to add the following lines
4817     case 0: // 0 croix diagonale
4818       fl_line(deltax+i0-epaisseur_point,deltay+j0-epaisseur_point,deltax+i0+epaisseur_point,deltay+j0+epaisseur_point,c);
4819       fl_line(deltax+i0-epaisseur_point,deltay+j0+epaisseur_point,deltax+i0+epaisseur_point,deltay+j0-epaisseur_point,c);
4820       break;
4821     default: // 4 nothing drawn
4822       break;
4823     }
4824   }
4825 
horiz_or_vert(const_iterateur jt,GIAC_CONTEXT)4826   int horiz_or_vert(const_iterateur jt,GIAC_CONTEXT){
4827     gen tmp(*(jt+1)-*jt),r,i;
4828     reim(tmp,r,i,contextptr);
4829     if (is_zero(r,contextptr)) return 1;
4830     if (is_zero(i,contextptr)) return 2;
4831     return 0;
4832   }
4833 
fltk_draw(Graph2d & Mon_image,const gen & g,double x_scale,double y_scale,int clip_x,int clip_y,int clip_w,int clip_h,GIAC_CONTEXT)4834   void fltk_draw(Graph2d & Mon_image,const gen & g,double x_scale,double y_scale,int clip_x,int clip_y,int clip_w,int clip_h,GIAC_CONTEXT){
4835     int deltax=0,deltay=STATUS_AREA_PX,fontsize=Mon_image.labelsize;
4836     if (g.type==_VECT){
4837       const vecteur & v=*g._VECTptr;
4838       const_iterateur it=v.begin(),itend=v.end();
4839       for (;it!=itend;++it)
4840 	fltk_draw(Mon_image,*it,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h,contextptr);
4841     }
4842     if (g.type!=_SYMB)
4843       return;
4844     unary_function_ptr s=g._SYMBptr->sommet;
4845     if (g._SYMBptr->feuille.type!=_VECT)
4846       return;
4847     vecteur f=*g._SYMBptr->feuille._VECTptr;
4848     int mxw=LCD_WIDTH_PX,myw=LCD_HEIGHT_PX-STATUS_AREA_PX;
4849     double i0,j0,i0save,j0save,i1,j1;
4850     int fs=f.size();
4851     if ((fs==4) && (s==at_parameter)){
4852       return ;
4853     }
4854     string the_legend;
4855     vecteur style(get_style(f,the_legend));
4856     int styles=style.size();
4857     // color
4858     int ensemble_attributs = style.front().val;
4859     bool hidden_name = false;
4860     if (style.front().type==_ZINT){
4861       ensemble_attributs = mpz_get_si(*style.front()._ZINTptr);
4862       hidden_name=true;
4863     }
4864     else
4865       hidden_name=ensemble_attributs<0;
4866     int width           =(ensemble_attributs & 0x00070000) >> 16; // 3 bits
4867     int epaisseur_point =(ensemble_attributs & 0x00380000) >> 19; // 3 bits
4868     int type_line       =(ensemble_attributs & 0x01c00000) >> 22; // 3 bits
4869     if (type_line>4)
4870       type_line=(type_line-4)<<8;
4871     int type_point      =(ensemble_attributs & 0x0e000000) >> 25; // 3 bits
4872     int labelpos        =(ensemble_attributs & 0x30000000) >> 28; // 2 bits
4873     bool fill_polygon   =(ensemble_attributs & 0x40000000) >> 30;
4874     int couleur         =(ensemble_attributs & 0x0007ffff);
4875     epaisseur_point += 2;
4876     if (s==at_pnt){
4877       // f[0]=complex pnt or vector of complex pnts or symbolic
4878       // f[1] -> style
4879       // f[2] optional=label
4880       gen point=f[0];
4881       if (point.type==_VECT && point.subtype==_POINT__VECT)
4882 	return;
4883       if ( (f[0].type==_SYMB) && (f[0]._SYMBptr->sommet==at_curve) && (f[0]._SYMBptr->feuille.type==_VECT) && (f[0]._SYMBptr->feuille._VECTptr->size()) ){
4884 	// Mon_image.show_mouse_on_object=false;
4885 	point=f[0]._SYMBptr->feuille._VECTptr->back();
4886 	if (type_line>=4 && point.type==_VECT && point._VECTptr->size()>2){
4887 	  vecteur v=*point._VECTptr;
4888 	  int vs=v.size()/2; // 3 -> 1
4889 	  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)){
4890 	    bool logx=Mon_image.display_mode & 0x400,logy=Mon_image.display_mode & 0x800;
4891 	    checklog_fl_line(i0,j0,i1,j1,deltax,deltay,logx,logy,Mon_image.window_xmin,x_scale,Mon_image.window_ymax,y_scale,couleur);
4892 	    double dx=i0-i1,dy=j0-j1;
4893 	    petite_fleche(i1,j1,dx,dy,deltax,deltay,width+3,couleur);
4894 	  }
4895 	}
4896       }
4897       if (is_undef(point))
4898 	return;
4899       // fl_line_style(type_line,width+1,0);
4900       if (point.type==_SYMB) {
4901 	if (point._SYMBptr->sommet==at_cercle){
4902 	  vecteur v=*point._SYMBptr->feuille._VECTptr;
4903 	  gen diametre=remove_at_pnt(v[0]);
4904 	  gen e1=diametre._VECTptr->front().evalf_double(1,contextptr),e2=diametre._VECTptr->back().evalf_double(1,contextptr);
4905 	  gen centre=rdiv(e1+e2,2.0,contextptr);
4906 	  gen e12=e2-e1;
4907 	  double ex=evalf_double(re(e12,contextptr),1,contextptr)._DOUBLE_val,ey=evalf_double(im(e12,contextptr),1,contextptr)._DOUBLE_val;
4908 	  if (!Mon_image.findij(centre,x_scale,y_scale,i0,j0,contextptr))
4909 	    return;
4910 	  gen diam=std::sqrt(ex*ex+ey*ey);
4911 	  gen angle=std::atan2(ey,ex);
4912 	  gen a1=v[1].evalf_double(1,contextptr),a2=v[2].evalf_double(1,contextptr);
4913 	  bool full=v[1]==0 && v[2]==cst_two_pi;
4914 	  if ( (diam.type==_DOUBLE_) && (a1.type==_DOUBLE_) && (a2.type==_DOUBLE_) ){
4915 	    i1=diam._DOUBLE_val*x_scale/2.0;
4916 	    j1=diam._DOUBLE_val*y_scale/2.0;
4917 	    double a1d=a1._DOUBLE_val,a2d=a2._DOUBLE_val,angled=angle._DOUBLE_val;
4918 	    bool changer_sens=a1d>a2d;
4919 	    if (changer_sens){
4920 	      double tmp=a1d;
4921 	      a1d=a2d;
4922 	      a2d=tmp;
4923 	    }
4924 	    double anglei=(angled+a1d),anglef=(angled+a2d),anglem=(anglei+anglef)/2;
4925 	    if (fill_polygon)
4926 	      fl_pie(deltax+round(i0-i1),deltay+round(j0-j1),round(2*i1),round(2*j1),full?0:anglei*180/M_PI+.5,full?360:anglef*180/M_PI+.5,couleur,false);
4927 	    else {
4928 	      fl_arc(deltax+round(i0-i1),deltay+round(j0-j1),round(2*i1),round(2*j1),full?0:anglei*180/M_PI+.5,full?360:anglef*180/M_PI+.5,couleur);
4929 	      if (v.size()>=4){ // if cercle has the optionnal 5th arg
4930 		if (v[3]==2)
4931 		  petite_fleche(i0+i1*std::cos(anglem),j0-j1*std::sin(anglem),-i1*std::sin(anglem),-j1*std::cos(anglem),deltax,deltay,width,couleur);
4932 		else {
4933 		  if (changer_sens)
4934 		    petite_fleche(i0+i1*std::cos(anglei),j0-j1*std::sin(anglei),-i1*std::sin(anglei),-j1*std::cos(anglei),deltax,deltay,width,couleur);
4935 		  else
4936 		    petite_fleche(i0+i1*std::cos(anglef),j0-j1*std::sin(anglef),i1*std::sin(anglef),j1*std::cos(anglef),deltax,deltay,width,couleur);
4937 		}
4938 	      }
4939 	    }
4940 	    // Label a few degrees from the start angle,
4941 	    // FIXME should use labelpos
4942 	    double anglel=angled+a1d+0.3;
4943 	    if (v.size()>=4 && v[3]==2)
4944 	      anglel=angled+(0.45*a1d+0.55*a2d);
4945 	    i0=i0+i1*std::cos(anglel);
4946 	    j0=j0-j1*std::sin(anglel);
4947 	    if (!hidden_name)
4948 	      draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0,couleur,contextptr);
4949 	    return;
4950 	  }
4951 	} // end circle
4952 #if 0
4953 	if (point._SYMBptr->sommet==at_legende){
4954 	  gen & f=point._SYMBptr->feuille;
4955 	  if (f.type==_VECT && f._VECTptr->size()==3){
4956 	    vecteur & fv=*f._VECTptr;
4957 	    if (fv[0].type==_VECT && fv[0]._VECTptr->size()>=2 && fv[1].type==_STRNG && fv[2].type==_INT_){
4958 	      vecteur & fvv=*fv[0]._VECTptr;
4959 	      if (fvv[0].type==_INT_ && fvv[1].type==_INT_){
4960 		int dx=0,dy=0;
4961 		string legendes(*fv[1]._STRNGptr);
4962 		find_dxdy(legendes,labelpos,fontsize,dx,dy);
4963 		text_print(fontsize,legendes.c_str(),deltax+fvv[0].val+dx,deltay+fvv[1].val+dy,fv[2].val);
4964 	      }
4965 	    }
4966 	  }
4967 	}
4968 #endif
4969       } // end point.type==_SYMB
4970       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
4971 	if (!Mon_image.findij((point.type==_VECT?point._VECTptr->front():point),x_scale,y_scale,i0,j0,contextptr))
4972 	  return;
4973 	if (i0>0 && i0<mxw && j0>0 && j0<myw)
4974 	  fltk_point(deltax,deltay,round(i0),round(j0),epaisseur_point,type_point,couleur);
4975 	if (!hidden_name)
4976 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0,couleur,contextptr);
4977 	return;
4978       }
4979       // path
4980       const_iterateur jt=point._VECTptr->begin(),jtend=point._VECTptr->end();
4981       if (jt==jtend)
4982 	return;
4983       bool logx=Mon_image.display_mode & 0x400,logy=Mon_image.display_mode & 0x800;
4984       if (jt->type==_VECT)
4985 	return;
4986       if ( (type_point || epaisseur_point>2) && type_line==0 && width==0){
4987 	for (;jt!=jtend;++jt){
4988 	  if (!Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr))
4989 	    return;
4990 	  if (i0>0 && i0<mxw && j0>0 && j0<myw)
4991 	    fltk_point(deltax,deltay,round(i0),round(j0),epaisseur_point,type_point,couleur);
4992 	}
4993 	if (!hidden_name)
4994 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0,couleur,contextptr);
4995 	return;
4996       }
4997       // initial point
4998       if (!Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr))
4999 	return;
5000       i0save=i0;
5001       j0save=j0;
5002       if (fill_polygon){
5003 	if (jtend-jt==5 && *(jt+4)==*jt){
5004 	  // check rectangle parallel to axes -> draw_rectangle (filled)
5005 	  int cote1=horiz_or_vert(jt,contextptr);
5006 	  if (cote1 && horiz_or_vert(jt+1,contextptr)==3-cote1 && horiz_or_vert(jt+2,contextptr)==cote1 && horiz_or_vert(jt+3,contextptr)==3-cote1){
5007 	    if (!Mon_image.findij(*(jt+2),x_scale,y_scale,i0,j0,contextptr))
5008 	      return;
5009 	    int x,y,w,h;
5010 	    if (i0<i0save){
5011 	      x=i0;
5012 	      w=i0save-i0;
5013 	    }
5014 	    else {
5015 	      x=i0save;
5016 	      w=i0-i0save;
5017 	    }
5018 	    if (j0<j0save){
5019 	      y=j0;
5020 	      h=j0save-j0;
5021 	    }
5022 	    else {
5023 	      y=j0save;
5024 	      h=j0-j0save;
5025 	    }
5026 	    draw_rectangle(deltax+x,deltay+y,w,h,couleur);
5027 	    if (!hidden_name)
5028 	      draw_legende(f,deltax+x,deltay+y,labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0,couleur,contextptr);
5029 	    return;
5030 	  }
5031 	} // end rectangle check
5032 	bool closed=*jt==*(jtend-1);
5033 	vector< vector<int> > vi(jtend-jt+(closed?0:1),vector<int>(2));
5034 	for (int pos=0;jt!=jtend;++pos,++jt){
5035 	  if (!Mon_image.findij(*jt,x_scale,y_scale,i0,j0,contextptr))
5036 	    return;
5037 	  vi[pos][0]=i0+deltax;
5038 	  vi[pos][1]=j0+deltay;
5039 	}
5040 	if (!closed)
5041 	  vi.back()=vi.front();
5042 	draw_filled_polygon(vi,0,LCD_WIDTH_PX,0,LCD_HEIGHT_PX,couleur);
5043 	if (!hidden_name)
5044 	  draw_legende(f,round(i0),round(j0),labelpos,&Mon_image,clip_x,clip_y,clip_w,clip_h,0,0,couleur,contextptr);
5045 	return;
5046       }
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,couleur);
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,couleur,contextptr);
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,couleur);
5062 	  if (point.subtype==_VECTOR__VECT){
5063 	    double dx=i0-i1,dy=j0-j1;
5064 	    petite_fleche(i1,j1,dx,dy,deltax,deltay,width,couleur);
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=absdouble(deltai);
5085 	double deltaj=j1-j0save,adeltaj=absdouble(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,couleur);
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,couleur);
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,couleur);
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,couleur);
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,couleur,contextptr);
5139       }
5140     } // end pnt subcase
5141   }
5142 #endif
5143 
5144   // return a vector of values with simple decimal representation
5145   // between xmin/xmax or including xmin/xmax (if bounds is true)
ticks(double xmin,double xmax,bool bounds)5146   vecteur ticks(double xmin,double xmax,bool bounds){
5147     if (xmax<xmin)
5148       swapdouble(xmin,xmax);
5149     double dx=xmax-xmin;
5150     vecteur res;
5151     if (dx==0)
5152       return res;
5153     double d=std::pow(10.0,std::floor(std::log10(dx)));
5154     if (dx<2*d)
5155       d=d/5;
5156     else {
5157       if (dx<5*d)
5158 	d=d/2;
5159     }
5160     double x1=std::floor(xmin/d)*d;
5161     double x2=(bounds?std::ceil(xmax/d):std::floor(xmax/d))*d;
5162     for (double x=x1+(bounds?0:d);x<=x2;x+=d){
5163       if (absdouble(x-int(x+.5))<1e-6*d)
5164 	res.push_back(int(x+.5));
5165       else
5166 	res.push_back(x);
5167     }
5168     return res;
5169   }
5170 
draw()5171   void Graph2d::draw(){
5172     int save_clip_ymin=clip_ymin;
5173     clip_ymin=STATUS_AREA_PX;
5174     int horizontal_pixels=LCD_WIDTH_PX,vertical_pixels=LCD_HEIGHT_PX-STATUS_AREA_PX,deltax=0,deltay=STATUS_AREA_PX,clip_x=0,clip_y=0,clip_w=horizontal_pixels,clip_h=vertical_pixels;
5175     drawRectangle(0, STATUS_AREA_PX, horizontal_pixels, vertical_pixels,COLOR_WHITE);
5176     // Draw axis
5177     double I0,J0;
5178     findij(zero,x_scale,y_scale,I0,J0,contextptr); // origin
5179     int i_0=round(I0),j_0=round(J0);
5180     if (show_axes &&  (window_ymax>=0) && (window_ymin<=0)){ // X-axis
5181       vecteur aff; int affs;
5182       char ch[256];
5183       check_fl_line(deltax,deltay+j_0,deltax+horizontal_pixels,deltay+j_0,clip_x,clip_y,clip_w,clip_h,0,0,_GREEN);
5184       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,_CYAN);
5185       aff=ticks(window_xmin,window_xmax,true);
5186       affs=aff.size();
5187       for (int i=0;i<affs;++i){
5188 	double d=evalf_double(aff[i],1,contextptr)._DOUBLE_val;
5189 	if (fabs(d)<1e-6) strcpy(ch,"0"); else sprint_double(ch,d);
5190 	int delta=int(horizontal_pixels*(d-window_xmin)/(window_xmax-window_xmin));
5191 	int taille=strlen(ch)*9;
5192 	fl_line(delta,deltay+j_0,delta,deltay+j_0-4,_GREEN);
5193       }
5194       check_fl_draw(labelsize,"x",deltax+horizontal_pixels-40,deltay+j_0-4,clip_x,clip_y,clip_w,clip_h,0,0,_GREEN);
5195     }
5196     if ( show_axes && (window_xmax>=0) && (window_xmin<=0) ) {// Y-axis
5197       vecteur aff; int affs;
5198       char ch[256];
5199       check_fl_line(deltax+i_0,deltay,deltax+i_0,deltay+vertical_pixels,clip_x,clip_y,clip_w,clip_h,0,0,_RED);
5200       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,_CYAN);
5201       aff=ticks(window_ymin,window_ymax,true);
5202       affs=aff.size();
5203       int taille=5;
5204       for (int j=0;j<affs;++j){
5205 	double d=evalf_double(aff[j],1,contextptr)._DOUBLE_val;
5206 	if (fabs(d)<1e-6) strcpy(ch,"0"); else sprint_double(ch,d);
5207 	int delta=int(vertical_pixels*(window_ymax-d)/(window_ymax-window_ymin));
5208 	if (delta>=taille && delta<=vertical_pixels-taille){
5209 	  fl_line(deltax+i_0,STATUS_AREA_PX+delta,deltax+i_0+4,STATUS_AREA_PX+delta,_RED);
5210 	}
5211       }
5212       check_fl_draw(labelsize,"y",deltax+i_0+2,deltay+labelsize,clip_x,clip_y,clip_w,clip_h,0,0,_RED);
5213     }
5214 #if 0 // if ticks are enabled, don't forget to set freeze to false
5215     // Ticks
5216     if (show_axes && (horizontal_pixels)/(x_scale*x_tick) < 40 && vertical_pixels/(y_tick*y_scale) <40  ){
5217       if (x_tick>0 && y_tick>0 ){
5218 	double nticks=(horizontal_pixels-I0)/(x_scale*x_tick);
5219 	double mticks=(vertical_pixels-J0)/(y_tick*y_scale);
5220 	int count=0;
5221 	for (int ii=int(-I0/(x_tick*x_scale));ii<=nticks;++ii){
5222 	  int iii=int(I0+ii*x_scale*x_tick+.5);
5223 	  for (int jj=int(-J0/(y_tick*y_scale));jj<=mticks && count<1600;++jj,++count){
5224 	    int jjj=int(J0+jj*y_scale*y_tick+.5);
5225 	    check_fl_point(deltax+iii,deltay+jjj,clip_x,clip_y,clip_w,clip_h,0,0,COLOR_BLACK);
5226 	  }
5227 	}
5228       }
5229     }
5230 #endif
5231     if (show_axes){
5232       int taille,affs,delta;
5233       vecteur aff;
5234       char ch[256];
5235       // X
5236       aff=ticks(window_xmin,window_xmax,true);
5237       affs=aff.size();
5238       for (int i=0;i<affs;++i){
5239 	double d=evalf_double(aff[i],1,contextptr)._DOUBLE_val;
5240 	sprint_double(ch,d);
5241 	delta=int(horizontal_pixels*(d-window_xmin)/(window_xmax-window_xmin));
5242 	taille=strlen(ch)*9;
5243 	fl_line(delta,vertical_pixels+STATUS_AREA_PX-6,delta,vertical_pixels+STATUS_AREA_PX-1,_GREEN);
5244 	if (delta>=taille/2 && delta<=horizontal_pixels){
5245 	  text_print(10,ch,delta-taille/2,vertical_pixels+STATUS_AREA_PX-7,_GREEN);
5246 	}
5247       }
5248       // Y
5249       aff=ticks(window_ymin,window_ymax,true);
5250       affs=aff.size();
5251       taille=5;
5252       for (int j=0;j<affs;++j){
5253 	double d=evalf_double(aff[j],1,contextptr)._DOUBLE_val;
5254 	sprint_double(ch,d);
5255 	delta=int(vertical_pixels*(window_ymax-d)/(window_ymax-window_ymin));
5256 	if (delta>=taille && delta<=vertical_pixels-taille){
5257 	  fl_line(horizontal_pixels-5,STATUS_AREA_PX+delta,horizontal_pixels-1,STATUS_AREA_PX+delta,_RED);
5258 	  text_print(10,ch,horizontal_pixels-strlen(ch)*9,STATUS_AREA_PX+delta+taille,_RED);
5259 	}
5260       }
5261     }
5262 
5263     // draw
5264     fltk_draw(*this,g,x_scale,y_scale,clip_x,clip_y,clip_w,clip_h,contextptr);
5265     clip_ymin=save_clip_ymin;
5266   }
5267 
left(double d)5268   void Graph2d::left(double d){
5269     window_xmin -= d;
5270     window_xmax -= d;
5271   }
5272 
right(double d)5273   void Graph2d::right(double d){
5274     window_xmin += d;
5275     window_xmax += d;
5276   }
5277 
up(double d)5278   void Graph2d::up(double d){
5279     window_ymin += d;
5280     window_ymax += d;
5281   }
5282 
down(double d)5283   void Graph2d::down(double d){
5284     window_ymin -= d;
5285     window_ymax -= d;
5286   }
5287 
draw()5288   void Turtle::draw(){
5289     const int deltax=0,deltay=0;
5290     int horizontal_pixels=LCD_WIDTH_PX-2*giac::COORD_SIZE;
5291     // Check for fast redraw
5292     // Then redraw the background
5293     drawRectangle(deltax, deltay, LCD_WIDTH_PX, LCD_HEIGHT_PX,COLOR_WHITE);
5294     if (turtleptr &&
5295 #ifdef TURTLETAB
5296 	turtle_stack_size
5297 #else
5298 	!turtleptr->empty()
5299 #endif
5300 	){
5301       if (turtlezoom>8)
5302 	turtlezoom=8;
5303       if (turtlezoom<0.125)
5304 	turtlezoom=0.125;
5305       // check that position is not out of screen
5306 #ifdef TURTLETAB
5307       logo_turtle t=turtleptr[turtle_stack_size-1];
5308 #else
5309       logo_turtle t=turtleptr->back();
5310 #endif
5311       double x=turtlezoom*(t.x-turtlex);
5312       if (x<0)
5313 	turtlex += int(x/turtlezoom);
5314       if (x>=LCD_WIDTH_PX-10)
5315 	turtlex += int((x-LCD_WIDTH_PX+10)/turtlezoom);
5316       double y=turtlezoom*(t.y-turtley);
5317       if (y<0)
5318 	turtley += int(y/turtlezoom);
5319       if (y>LCD_HEIGHT_PX-10)
5320 	turtley += int((y-LCD_HEIGHT_PX+10)/turtlezoom);
5321     }
5322 #if 0
5323     if (maillage & 0x3){
5324       fl_color(FL_BLACK);
5325       double xdecal=std::floor(turtlex/10.0)*10;
5326       double ydecal=std::floor(turtley/10.0)*10;
5327       if ( (maillage & 0x3)==1){
5328 	for (double i=xdecal;i<LCD_WIDTH_PX+xdecal;i+=10){
5329 	  for (double j=ydecal;j<LCD_HEIGHT_PX+ydecal;j+=10){
5330 	    fl_point(deltax+int((i-turtlex)*turtlezoom+.5),deltay+LCD_HEIGHT_PX-int((j-turtley)*turtlezoom+.5));
5331 	  }
5332 	}
5333       }
5334       else {
5335 	double dj=std::sqrt(3.0)*10,i0=xdecal;
5336 	for (double j=ydecal;j<LCD_HEIGHT_PX+ydecal;j+=dj){
5337 	  int J=deltay+int(LCD_HEIGHT_PX-(j-turtley)*turtlezoom);
5338 	  for (double i=i0;i<LCD_WIDTH_PX+xdecal;i+=10){
5339 	    fl_point(deltax+int((i-turtlex)*turtlezoom+.5),J);
5340 	  }
5341 	  i0 += dj;
5342 	  while (i0>=10)
5343 	    i0 -= 10;
5344 	}
5345       }
5346     }
5347 #endif
5348     // Show turtle position/cap
5349     if (turtleptr &&
5350 #ifdef TURTLETAB
5351 	turtle_stack_size &&
5352 #else
5353 	!turtleptr->empty() &&
5354 #endif
5355 	!(maillage & 0x4)){
5356 #ifdef TURTLETAB
5357       logo_turtle turtle=turtleptr[turtle_stack_size-1];
5358 #else
5359       logo_turtle turtle=turtleptr->back();
5360 #endif
5361       drawRectangle(deltax+horizontal_pixels,deltay,LCD_WIDTH_PX-horizontal_pixels,2*COORD_SIZE,_YELLOW);
5362       // drawRectangle(deltax, deltay, LCD_WIDTH_PX, LCD_HEIGHT_PX,COLOR_BLACK);
5363       char buf[32];
5364       sprintf(buf,"x %i   ",int(turtle.x+.5));
5365       text_print(18,buf,deltax+horizontal_pixels,deltay+(2*COORD_SIZE)/3-2,COLOR_BLACK,_YELLOW);
5366       sprintf(buf,"y %i   ",int(turtle.y+.5));
5367       text_print(18,buf,deltax+horizontal_pixels,deltay+(4*COORD_SIZE)/3-3,COLOR_BLACK,_YELLOW);
5368       sprintf(buf,"t %i   ",int(turtle.theta+.5));
5369       text_print(18,buf,deltax+horizontal_pixels,deltay+2*COORD_SIZE-4,COLOR_BLACK,_YELLOW);
5370     }
5371     // draw turtle Logo
5372     if (turtleptr){
5373 #ifdef TURTLETAB
5374       int l=turtle_stack_size;
5375 #else
5376       int l=turtleptr->size();
5377 #endif
5378       if (l>0){
5379 #ifdef TURTLETAB
5380 	logo_turtle prec =turtleptr[0];
5381 #else
5382 	logo_turtle prec =(*turtleptr)[0];
5383 #endif
5384 	int sp=speed;
5385 	for (int k=1;k<l;++k){
5386 	  if (k>=2 && sp){
5387 	    sync_screen();
5388 	    for (int i=0;i<speed;++i){
5389 	      for (int j=0;j<1000;++j){
5390 		if (iskeydown(5) || iskeydown(4) || iskeydown(22)){
5391 		  sp=0;
5392 		  break;
5393 		}
5394 	      }
5395 	    }
5396 	  }
5397 #ifdef TURTLETAB
5398 	  logo_turtle current =(turtleptr)[k];
5399 #else
5400 	  logo_turtle current =(*turtleptr)[k];
5401 #endif
5402 #if 1
5403 	  if (current.s>=0){ // Write a string
5404 	    //cout << current.radius << " " << current.s << endl;
5405 	    if (current.s<ecristab().size())
5406 	      text_print(current.radius,ecristab()[current.s].c_str(),int(deltax+turtlezoom*(current.x-turtlex)),int(deltay+LCD_HEIGHT_PX-turtlezoom*(current.y-turtley)),current.color);
5407 	  }
5408 	  else
5409 #endif
5410 	    {
5411 	      if (current.radius>0){
5412 		int r=current.radius & 0x1ff; // bit 0-8
5413 		double theta1,theta2;
5414 		if (current.direct){
5415 		  theta1=prec.theta+double((current.radius >> 9) & 0x1ff); // bit 9-17
5416 		  theta2=prec.theta+double((current.radius >> 18) & 0x1ff); // bit 18-26
5417 		}
5418 		else {
5419 		  theta1=prec.theta-double((current.radius >> 9) & 0x1ff); // bit 9-17
5420 		  theta2=prec.theta-double((current.radius >> 18) & 0x1ff); // bit 18-26
5421 		}
5422 		bool rempli=(current.radius >> 27) & 0x1;
5423 		bool seg=(current.radius >> 28) & 0x1;
5424 		double angle;
5425 		int x,y,R;
5426 		R=int(2*turtlezoom*r+.5);
5427 		angle = M_PI/180*(theta2-90);
5428 		if (current.direct){
5429 		  x=int(turtlezoom*(current.x-turtlex-r*std::cos(angle) - r)+.5);
5430 		  y=int(turtlezoom*(current.y-turtley-r*std::sin(angle) + r)+.5);
5431 		}
5432 		else {
5433 		  x=int(turtlezoom*(current.x-turtlex+r*std::cos(angle) -r)+.5);
5434 		  y=int(turtlezoom*(current.y-turtley+r*std::sin(angle) +r)+.5);
5435 		}
5436 		if (current.direct){
5437 		  if (rempli)
5438 		    fl_pie(deltax+x,deltay+LCD_HEIGHT_PX-y,R,R,theta1-90,theta2-90,current.color,seg);
5439 		  else
5440 		    fl_arc(deltax+x,deltay+LCD_HEIGHT_PX-y,R,R,theta1-90,theta2-90,current.color);
5441 		}
5442 		else {
5443 		  if (rempli)
5444 		    fl_pie(deltax+x,deltay+LCD_HEIGHT_PX-y,R,R,90+theta2,90+theta1,current.color,seg);
5445 		  else
5446 		    fl_arc(deltax+x,deltay+LCD_HEIGHT_PX-y,R,R,90+theta2,90+theta1,current.color);
5447 		}
5448 	      } // end radius>0
5449 	      else {
5450 		if (prec.mark){
5451 		  fl_line(deltax+int(turtlezoom*(prec.x-turtlex)+.5),deltay+int(LCD_HEIGHT_PX+turtlezoom*(turtley-prec.y)+.5),deltax+int(turtlezoom*(current.x-turtlex)+.5),deltay+int(LCD_HEIGHT_PX+turtlezoom*(turtley-current.y)+.5),prec.color);
5452 		}
5453 	      }
5454 	      if (current.radius<-1 && k+current.radius>=0){
5455 		// poly-line from (*turtleptr)[k+current.radius] to (*turtleptr)[k]
5456 		vector< vector<int> > vi(1-current.radius,vector<int>(2));
5457 		for (int i=0;i>=current.radius;--i){
5458 #ifdef TURTLETAB
5459 		  logo_turtle & t=(turtleptr)[k+i];
5460 #else
5461 		  logo_turtle & t=(*turtleptr)[k+i];
5462 #endif
5463 		  vi[-i][0]=deltax+turtlezoom*(t.x-turtlex);
5464 		  vi[-i][1]=deltay+LCD_HEIGHT_PX+turtlezoom*(turtley-t.y);
5465 		  //*logptr(contextptr) << i << " " << vi[-i][0] << " " << vi[-i][1] << endl;
5466 		}
5467 		//vi.back()=vi.front();
5468 		draw_filled_polygon(vi,0,LCD_WIDTH_PX,24,LCD_HEIGHT_PX,current.color);
5469 	      }
5470 	    } // end else (non-string turtle record)
5471 	  prec=current;
5472 	} // end for (all turtle records)
5473 #ifdef TURTLETAB
5474 	logo_turtle & t = (turtleptr)[l-1];
5475 #else
5476 	logo_turtle & t = (*turtleptr)[l-1];
5477 #endif
5478 	int x=int(turtlezoom*(t.x-turtlex)+.5);
5479 	int y=int(turtlezoom*(t.y-turtley)+.5);
5480 	double cost=std::cos(t.theta*deg2rad_d);
5481 	double sint=std::sin(t.theta*deg2rad_d);
5482 	int Dx=int(turtlezoom*t.turtle_length*cost/2+.5);
5483 	int Dy=int(turtlezoom*t.turtle_length*sint/2+.5);
5484 	if (t.visible){
5485 	  fl_line(deltax+x+Dy,deltay+LCD_HEIGHT_PX-(y-Dx),deltax+x-Dy,deltay+LCD_HEIGHT_PX-(y+Dx),t.color);
5486 	  int c=t.color;
5487 	  if (!t.mark)
5488 	    c=t.color ^ 0x7777;
5489 	  fl_line(deltax+x+Dy,deltay+LCD_HEIGHT_PX-(y-Dx),deltax+x+3*Dx,deltay+LCD_HEIGHT_PX-(y+3*Dy),c);
5490 	  fl_line(deltax+x-Dy,deltay+LCD_HEIGHT_PX-(y+Dx),deltax+x+3*Dx,deltay+LCD_HEIGHT_PX-(y+3*Dy),c);
5491 	}
5492       }
5493       return;
5494     } // End logo mode
5495   }
5496 
5497 
displaygraph(const giac::gen & ge,GIAC_CONTEXT)5498   int displaygraph(const giac::gen & ge,GIAC_CONTEXT){
5499     // graph display
5500     //if (aborttimer > 0) { Timer_Stop(aborttimer); Timer_Deinstall(aborttimer);}
5501     xcas::Graph2d gr(ge,contextptr);
5502     gr.show_axes=true;
5503     // initial setting for x and y
5504     if (ge.type==_VECT){
5505       const_iterateur it=ge._VECTptr->begin(),itend=ge._VECTptr->end();
5506       for (;it!=itend;++it){
5507 	if (it->is_symb_of_sommet(at_equal)){
5508 	  const gen & f=it->_SYMBptr->feuille;
5509 	  gen & optname = f._VECTptr->front();
5510 	  gen & optvalue= f._VECTptr->back();
5511 	  if (optname.val==_AXES && optvalue.type==_INT_)
5512 	    gr.show_axes=optvalue.val;
5513 	  if (optname.type==_INT_ && optname.subtype == _INT_PLOT && optname.val>=_GL_X && optname.val<=_GL_Z && optvalue.is_symb_of_sommet(at_interval)){
5514 	    //*logptr(contextptr) << optname << " " << optvalue << endl;
5515 	    gen optvf=evalf_double(optvalue._SYMBptr->feuille,1,contextptr);
5516 	    if (optvf.type==_VECT && optvf._VECTptr->size()==2){
5517 	      gen a=optvf._VECTptr->front();
5518 	      gen b=optvf._VECTptr->back();
5519 	      if (a.type==_DOUBLE_ && b.type==_DOUBLE_){
5520 		switch (optname.val){
5521 		case _GL_X:
5522 		  gr.window_xmin=a._DOUBLE_val;
5523 		  gr.window_xmax=b._DOUBLE_val;
5524 		  gr.update();
5525 		  break;
5526 		case _GL_Y:
5527 		  gr.window_ymin=a._DOUBLE_val;
5528 		  gr.window_ymax=b._DOUBLE_val;
5529 		  gr.update();
5530 		  break;
5531 		}
5532 	      }
5533 	    }
5534 	  }
5535 	}
5536       }
5537     }
5538     // UI
5539 #ifdef NSPIRE_NEWLIB
5540     DefineStatusMessage((char*)"+-: zoom, pad: move, esc: quit", 1, 0, 0);
5541 #else
5542     DefineStatusMessage((char*)"+-: zoom, pad: move, EXIT: quit", 1, 0, 0);
5543 #endif
5544     // EnableStatusArea(2);
5545     for (;;){
5546       gr.draw();
5547       DisplayStatusArea();
5548       // int x=0,y=LCD_HEIGHT_PX-STATUS_AREA_PX-17;
5549       // PrintMini(&x,&y,(unsigned char *)"menu",0x04,0xffffffff,0,0,COLOR_BLACK,COLOR_WHITE,1,0);
5550       int key=-1;
5551       GetKey(&key);
5552       if (key==KEY_SHUTDOWN)
5553 	return key;
5554 #if 1
5555       if (key==KEY_CTRL_CATALOG || key==KEY_BOOK){
5556 	char menu_xmin[32],menu_xmax[32],menu_ymin[32],menu_ymax[32];
5557 	string s;
5558 	s="xmin "+print_DOUBLE_(gr.window_xmin,contextptr);
5559 	strcpy(menu_xmin,s.c_str());
5560 	s="xmax "+print_DOUBLE_(gr.window_xmax,contextptr);
5561 	strcpy(menu_xmax,s.c_str());
5562 	s="ymin "+print_DOUBLE_(gr.window_ymin,contextptr);
5563 	strcpy(menu_ymin,s.c_str());
5564 	s="ymax "+print_DOUBLE_(gr.window_ymax,contextptr);
5565 	strcpy(menu_ymax,s.c_str());
5566 	Menu smallmenu;
5567 	smallmenu.numitems=12;
5568 	MenuItem smallmenuitems[smallmenu.numitems];
5569 	smallmenu.items=smallmenuitems;
5570 	smallmenu.height=12;
5571 	//smallmenu.title = "KhiCAS";
5572 	smallmenuitems[0].text = (char *) menu_xmin;
5573 	smallmenuitems[1].text = (char *) menu_xmax;
5574 	smallmenuitems[2].text = (char *) menu_ymin;
5575 	smallmenuitems[3].text = (char *) menu_ymax;
5576 	smallmenuitems[4].text = (char*) "Orthonormalize /";
5577 	smallmenuitems[5].text = (char*) "Autoscale *";
5578 	smallmenuitems[6].text = (char *) ("Zoom in +");
5579 	smallmenuitems[7].text = (char *) ("Zoom out -");
5580 	smallmenuitems[8].text = (char *) ("Y-Zoom out (-)");
5581 	smallmenuitems[9].text = (char*) ((lang==1)?"Voir axes":"Show axes");
5582 	smallmenuitems[10].text = (char*) ((lang==1)?"Cacher axes":"Hide axes");
5583 	smallmenuitems[11].text = (char*)((lang==1)?"Quitter":"Quit");
5584 	int sres = doMenu(&smallmenu);
5585 	if(sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) {
5586 	  const char * ptr=0;
5587 	  string s1; double d;
5588 	  if (smallmenu.selection==1){
5589 	    if (inputdouble(menu_xmin,d,contextptr)){
5590 	      gr.window_xmin=d;
5591 	      gr.update();
5592 	    }
5593 	  }
5594 	  if (smallmenu.selection==2){
5595 	    if (inputdouble(menu_xmax,d,contextptr)){
5596 	      gr.window_xmax=d;
5597 	      gr.update();
5598 	    }
5599 	  }
5600 	  if (smallmenu.selection==3){
5601 	    if (inputdouble(menu_ymin,d,contextptr)){
5602 	      gr.window_ymin=d;
5603 	      gr.update();
5604 	    }
5605 	  }
5606 	  if (smallmenu.selection==4){
5607 	    if (inputdouble(menu_ymax,d,contextptr)){
5608 	      gr.window_ymax=d;
5609 	      gr.update();
5610 	    }
5611 	  }
5612 	  if (smallmenu.selection==5)
5613 	    gr.orthonormalize();
5614 	  if (smallmenu.selection==6)
5615 	    gr.autoscale();
5616 	  if (smallmenu.selection==7)
5617 	    gr.zoom(0.7);
5618 	  if (smallmenu.selection==8)
5619 	    gr.zoom(1/0.7);
5620 	  if (smallmenu.selection==9)
5621 	    gr.zoomy(1/0.7);
5622 	  if (smallmenu.selection==10)
5623 	    gr.show_axes=true;
5624 	  if (smallmenu.selection==11)
5625 	    gr.show_axes=false;
5626 	  if (smallmenu.selection==12)
5627 	    break;
5628 	}
5629       }
5630 #endif
5631       if (key==KEY_CTRL_EXIT || key==KEY_CTRL_OK){
5632 	os_hide_graph();
5633 	break;
5634       }
5635       if (key==KEY_CTRL_UP){ gr.up((gr.window_ymax-gr.window_ymin)/5); }
5636       if (key==KEY_CTRL_PAGEUP) { gr.up((gr.window_ymax-gr.window_ymin)/2); }
5637       if (key==KEY_CTRL_DOWN) { gr.down((gr.window_ymax-gr.window_ymin)/5); }
5638       if (key==KEY_CTRL_PAGEDOWN) { gr.down((gr.window_ymax-gr.window_ymin)/2);}
5639       if (key==KEY_CTRL_LEFT) { gr.left((gr.window_xmax-gr.window_xmin)/5); }
5640       if (key==KEY_SHIFT_LEFT) { gr.left((gr.window_xmax-gr.window_xmin)/2); }
5641       if (key==KEY_CTRL_RIGHT) { gr.right((gr.window_xmax-gr.window_xmin)/5); }
5642       if (key==KEY_SHIFT_RIGHT) { gr.right((gr.window_xmax-gr.window_xmin)/5); }
5643       if (key==KEY_CHAR_PLUS) {
5644 	gr.zoom(0.7);
5645       }
5646       if (key==KEY_CHAR_MINUS){
5647 	gr.zoom(1/0.7);
5648       }
5649       if (key==KEY_CHAR_PMINUS){
5650 	gr.zoomy(1/0.7);
5651       }
5652       if (key==KEY_CHAR_MULT){
5653 	gr.autoscale();
5654       }
5655       if (key==KEY_CHAR_DIV) {
5656 	gr.orthonormalize();
5657       }
5658       if (key==KEY_CTRL_VARS) {
5659 	gr.show_axes=!gr.show_axes;
5660       }
5661     }
5662     // aborttimer = Timer_Install(0, check_execution_abort, 100); if (aborttimer > 0) { Timer_Start(aborttimer); }
5663     return 0;
5664   }
5665 
displaylogo()5666   int displaylogo(){
5667 #ifdef TURTLETAB
5668     xcas::Turtle t={tablogo,0,0,1,1,(short) turtle_speed};
5669 #else
5670     xcas::Turtle t={&turtle_stack(),0,0,1,1,(short) turtle_speed};
5671 #endif
5672 #ifdef NSPIRE_NEWLIB
5673     DefineStatusMessage((char*)"+-: zoom, pad: move, esc: quit", 1, 0, 0);
5674 #else
5675     DefineStatusMessage((char*)"+-: zoom, pad: move, EXIT: quit", 1, 0, 0);
5676 #endif
5677     DisplayStatusArea();
5678     bool redraw=true;
5679     while (1){
5680       int save_ymin=clip_ymin;
5681       clip_ymin=24;
5682       if (redraw)
5683 	t.draw();
5684       redraw=false;
5685       clip_ymin=save_ymin;
5686       int key;
5687       GetKey(&key);
5688       if (key==KEY_SHUTDOWN)
5689 	return key;
5690       if (key==KEY_CTRL_EXIT || key==KEY_CTRL_OK || key==KEY_PRGM_ACON || key==KEY_CTRL_MENU || key==KEY_CTRL_EXE || key==KEY_CTRL_VARS)
5691 	break;
5692       if (key==KEY_CTRL_UP){ t.turtley += 10; redraw=true; }
5693       if (key==KEY_CTRL_PAGEUP) { t.turtley += 100; redraw=true;}
5694       if (key==KEY_CTRL_DOWN) { t.turtley -= 10; redraw=true;}
5695       if (key==KEY_CTRL_PAGEDOWN) { t.turtley -= 100;redraw=true;}
5696       if (key==KEY_CTRL_LEFT) { t.turtlex -= 10; redraw=true;}
5697       if (key==KEY_SHIFT_LEFT) { t.turtlex -= 100; redraw=true;}
5698       if (key==KEY_CTRL_RIGHT) { t.turtlex += 10; redraw=true;}
5699       if (key==KEY_SHIFT_RIGHT) { t.turtlex += 100;redraw=true;}
5700       if (key==KEY_CHAR_PLUS) { t.turtlezoom *= 2;redraw=true;}
5701       if (key==KEY_CHAR_MINUS){ t.turtlezoom /= 2; redraw=true; }
5702       if (key==KEY_CHAR_MULT){ if (t.speed) t.speed *=2; else t.speed=10; redraw=true; }
5703       if (key==KEY_CHAR_DIV){ t.speed /=2; redraw=true; }
5704       if (key=='='){ redraw=true; }
5705     }
5706     os_hide_graph();
5707     return 0;
5708   }
5709 
ispnt(const gen & g)5710   bool ispnt(const gen & g){
5711     if (g.is_symb_of_sommet(giac::at_pnt))
5712       return true;
5713     if (g.type!=_VECT || g._VECTptr->empty())
5714       return false;
5715     return ispnt(g._VECTptr->back());
5716   }
5717 
translate_fkey(int & input_key)5718   void translate_fkey(int & input_key){
5719     if (input_key==KEY_CTRL_MIXEDFRAC) input_key=KEY_CTRL_F10;
5720     if (input_key==KEY_CTRL_FRACCNVRT) input_key=KEY_CTRL_F7;
5721     if (input_key==KEY_CHAR_LIST) input_key=KEY_CTRL_F9;
5722     if (input_key==KEY_CHAR_MAT) input_key=KEY_CTRL_F8;
5723     if (input_key==KEY_CTRL_PRGM) input_key=KEY_CTRL_F12;
5724     if (input_key==KEY_CTRL_FD) input_key=KEY_CTRL_F11;
5725     if (input_key==KEY_CHAR_ANGLE) input_key=KEY_CTRL_F13;
5726     if (input_key==KEY_CHAR_FRAC) input_key=KEY_CTRL_F14;
5727   }
5728 
eqw(const giac::gen & ge,bool editable,GIAC_CONTEXT)5729   giac::gen eqw(const giac::gen & ge,bool editable,GIAC_CONTEXT){
5730     bool edited=false;
5731     const int margin=16;
5732 #ifdef CURSOR
5733     Cursor_SetFlashOff();
5734 #endif
5735     giac::gen geq(_copy(ge,contextptr));
5736     // if (ge.type!=giac::_DOUBLE_ && giac::has_evalf(ge,geq,1,contextptr)) geq=giac::symb_equal(ge,geq);
5737     int line=-1,col=-1,nlines=0,ncols=0,listormat=0;
5738     xcas::Equation eq(0,0,geq,contextptr);
5739     giac::eqwdata eqdata=xcas::Equation_total_size(eq.data);
5740     if (eqdata.dx>1.5*LCD_WIDTH_PX || eqdata.dy>1.5*LCD_HEIGHT_PX){
5741       if (eqdata.dx>2.25*LCD_WIDTH_PX || eqdata.dy>2.25*LCD_HEIGHT_PX)
5742 	eq.attr=giac::attributs(14,COLOR_WHITE,COLOR_BLACK);
5743       else
5744 	eq.attr=giac::attributs(16,COLOR_WHITE,COLOR_BLACK);
5745       eq.data=0; // clear memory
5746       eq.data=xcas::Equation_compute_size(geq,eq.attr,LCD_WIDTH_PX,contextptr);
5747       eqdata=xcas::Equation_total_size(eq.data);
5748     }
5749     int dx=(eqdata.dx-LCD_WIDTH_PX)/2,dy=LCD_HEIGHT_PX-2*margin+eqdata.y;
5750     if (geq.type==_VECT){
5751       nlines=geq._VECTptr->size();
5752       if (eqdata.dx>=LCD_WIDTH_PX)
5753 	dx=-20; // line=nlines/2;
5754       //else
5755       if (geq.subtype!=_SEQ__VECT){
5756 	line=0;
5757 	listormat=1;
5758 	if (ckmatrix(geq)){
5759 	  ncols=geq._VECTptr->front()._VECTptr->size();
5760 	  if (eqdata.dy>=LCD_HEIGHT_PX-margin)
5761 	    dy=eqdata.y+eqdata.dy+32;// col=ncols/2;
5762 	  // else
5763 	  col=0;
5764 	  listormat=2;
5765 	}
5766       }
5767     }
5768     if (!listormat){
5769       xcas::Equation_select(eq.data,true);
5770       xcas::eqw_select_down(eq.data);
5771     }
5772     //cout << eq.data << endl;
5773     int firstrun=2;
5774     for (;;){
5775 #if 1
5776       if (firstrun==2){
5777 #ifdef NSPIRE_NEWLIB
5778 	DefineStatusMessage((char*)((lang==1)?"ctrl enter: eval, esc: quitte, ":"ctrl enter: eval, esc: exit"), 1, 0, 0);
5779 #else
5780 	DefineStatusMessage((char*)((lang==1)?"EXE: quitte, resultat dans last":"EXE: quit, result stored in last"), 1, 0, 0);
5781 #endif
5782 	DisplayStatusArea();
5783 	firstrun=1;
5784       }
5785       else
5786 	set_xcas_status();
5787 #else
5788       DefineStatusMessage((char*)"+-: zoom, pad: move, EXIT: quit", 1, 0, 0);
5789       EnableStatusArea(2);
5790       DisplayStatusArea();
5791 #endif
5792       gen value;
5793       if (listormat) // select line l, col c
5794 	xcas::eqw_select(eq.data,line,col,true,value);
5795       if (eqdata.dx>LCD_WIDTH_PX){
5796 	if (dx<-20)
5797 	  dx=-20;
5798 	if (dx>eqdata.dx-LCD_WIDTH_PX+20)
5799 	  dx=eqdata.dx-LCD_WIDTH_PX+20;
5800       }
5801 #define EQW_TAILLE 18
5802       if (eqdata.dy>LCD_HEIGHT_PX-2*EQW_TAILLE){
5803 	if (dy-eqdata.y<LCD_HEIGHT_PX-2*EQW_TAILLE)
5804 	  dy=eqdata.y+LCD_HEIGHT_PX-2*EQW_TAILLE;
5805 	if (dy-eqdata.y>eqdata.dy+32)
5806 	  dy=eqdata.y+eqdata.dy+32;
5807       }
5808       waitforvblank();
5809       drawRectangle(0, 0, LCD_WIDTH_PX, 205,COLOR_WHITE);
5810       // Bdisp_AllClr_VRAM();
5811       int save_clip_ymin=clip_ymin;
5812       clip_ymin=STATUS_AREA_PX;
5813       xcas::display(eq,dx,dy,contextptr);
5814 #if 1
5815       string menu("shift-1 ");
5816       menu += string(menu_f1);
5817       menu += "|2 ";
5818       menu += string(menu_f2);
5819       menu += "|3 undo|4 edt|5 +-|6 approx";
5820       drawRectangle(0,205,LCD_WIDTH_PX,17,22222);
5821       PrintMiniMini(0,205,menu.c_str(),4,22222,giac::_BLACK);
5822 #endif
5823       //draw_menu(2);
5824       clip_ymin=save_clip_ymin;
5825       int keyflag = GetSetupSetting( (unsigned int)0x14);
5826       if (firstrun){ // workaround for e.g. 1+x/2 partly not displayed
5827 	firstrun=0;
5828 	continue;
5829       }
5830       int key;
5831       //cout << eq.data << endl;
5832       GetKey(&key);
5833       if (key==KEY_SHUTDOWN)
5834 	return undef;
5835       bool alph=alphawasactive(&key);
5836       if (key==KEY_CTRL_OK || key==KEY_CTRL_MENU){
5837 	os_hide_graph();
5838 	if (edited && xcas::do_select(eq.data,true,value) && value.type==_EQW){
5839 	  //cout << "ok " << value._EQWptr->g << endl;
5840 	  DefineStatusMessage(((lang==1)?"resultat stocke dans last":"result stored in last"), 1, 0, 0);
5841 	  //DisplayStatusArea();
5842 	  giac::sto(value._EQWptr->g,giac::gen("last",contextptr),contextptr);
5843 	  return value._EQWptr->g;
5844 	}
5845 	//cout << "no " << eq.data << endl; if (value.type==_EQW) cout << value._EQWptr->g << endl ;
5846 	return geq;
5847       }
5848       if (key==KEY_CTRL_EXIT || key==KEY_CTRL_AC ){
5849 	if (!edited){
5850 	  os_hide_graph();
5851 	  return geq;
5852 	}
5853 	if (confirm(
5854 #ifdef NSPIRE_NEWLIB
5855 		    (lang==1)?"Vraiment abandonner?":"Really leave",(lang==1)?"esc: editeur,  enter: confirmer":"esc: editor,  enter: confirm"
5856 #else
5857 		    (lang==1)?"Vraiment abandonner?":"Really leave",(lang==1)?"Back: editeur,  OK: confirmer":"Back: editor,  OK: confirm"
5858 #endif
5859 		    )==KEY_CTRL_F1){
5860 	  os_hide_graph();
5861 	  return geq;
5862 	}
5863       }
5864       if (key==KEY_CTRL_F3)
5865 	key=KEY_CTRL_UNDO;
5866       if (key==KEY_CTRL_UNDO){
5867 	giac::swapgen(eq.undodata,eq.data);
5868 	if (listormat){
5869 	  xcas::do_select(eq.data,true,value);
5870 	  if (value.type==_EQW){
5871 	    gen g=eval(value._EQWptr->g,1,contextptr);
5872 	    if (g.type==_VECT){
5873 	      const vecteur & v=*g._VECTptr;
5874 	      nlines=v.size();
5875 	      if (line >= nlines)
5876 		line=nlines-1;
5877 	      if (col!=-1 &&v.front().type==_VECT){
5878 		ncols=v.front()._VECTptr->size();
5879 		if (col>=ncols)
5880 		  col=ncols-1;
5881 	      }
5882 	      xcas::do_select(eq.data,false,value);
5883 	      xcas::eqw_select(eq.data,line,col,true,value);
5884 	    }
5885 	  }
5886 	}
5887 	continue;
5888       }
5889       int redo=0;
5890       if (listormat){
5891 	if (key==KEY_CHAR_COMMA || key==KEY_CTRL_DEL ){
5892 	  xcas::do_select(eq.data,true,value);
5893 	  if (value.type==_EQW){
5894 	    gen g=eval(value._EQWptr->g,1,contextptr);
5895 	    if (g.type==_VECT){
5896 	      edited=true; eq.undodata=Equation_copy(eq.data);
5897 	      vecteur v=*g._VECTptr;
5898 	      if (key==KEY_CHAR_COMMA){
5899 		if (col==-1 || (line>0 && line==nlines-1)){
5900 		  v.insert(v.begin()+line+1,0*v.front());
5901 		  ++line; ++nlines;
5902 		}
5903 		else {
5904 		  v=mtran(v);
5905 		  v.insert(v.begin()+col+1,0*v.front());
5906 		  v=mtran(v);
5907 		  ++col; ++ncols;
5908 		}
5909 	      }
5910 	      else {
5911 		if (col==-1 || (nlines>=3 && line==nlines-1)){
5912 		  if (nlines>=(col==-1?2:3)){
5913 		    v.erase(v.begin()+line,v.begin()+line+1);
5914 		    if (line) --line;
5915 		    --nlines;
5916 		  }
5917 		}
5918 		else {
5919 		  if (ncols>=2){
5920 		    v=mtran(v);
5921 		    v.erase(v.begin()+col,v.begin()+col+1);
5922 		    v=mtran(v);
5923 		    if (col) --col; --ncols;
5924 		  }
5925 		}
5926 	      }
5927 	      geq=gen(v,g.subtype);
5928 	      key=0; redo=1;
5929 	      // continue;
5930 	    }
5931 	  }
5932 	}
5933       }
5934       bool ins=key==KEY_CHAR_STORE  || key==KEY_CHAR_RPAR || key==KEY_CHAR_LPAR || key==KEY_CHAR_COMMA || key==KEY_CTRL_PASTE || key==KEY_CTRL_F4;
5935       int xleft,ytop,xright,ybottom,gselpos; gen * gsel=0,*gselparent=0;
5936       if (key==KEY_CTRL_CLIP){
5937 	xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,0);
5938 	if (gsel==0)
5939 	  gsel==&eq.data;
5940 	// cout << "var " << g << " " << eq.data << endl;
5941 	if (xcas::do_select(*gsel,true,value) && value.type==_EQW){
5942 	  //cout << g << ":=" << value._EQWptr->g << endl;
5943 	  copy_clipboard(value._EQWptr->g.print(contextptr),true);
5944 	  continue;
5945 	}
5946       }
5947       if (key==KEY_CHAR_STORE){
5948 	int keyflag = GetSetupSetting( (unsigned int)0x14);
5949 	if (keyflag==0)
5950 	  handle_f5();
5951 	std::string varname;
5952 	if (inputline(((lang==1)?"Stocker la selection dans":"Save selection in",(lang==1)?"Nom de variable: ":"Variable name: "),0,varname,false,65,contextptr) && !varname.empty() && isalpha(varname[0])){
5953 	  giac::gen g(varname,contextptr);
5954 	  giac::gen ge(protecteval(g,1,contextptr));
5955 	  if (g.type!=_IDNT){
5956 	    invalid_varname();
5957 	    continue;
5958 	  }
5959 	  if (ge==g || confirm_overwrite()){
5960 	    vector<int> goto_sel;
5961 	    xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel);
5962 	    if (gsel==0)
5963 	      gsel==&eq.data;
5964 	    // cout << "var " << g << " " << eq.data << endl;
5965 	    if (xcas::do_select(*gsel,true,value) && value.type==_EQW){
5966 	      //cout << g << ":=" << value._EQWptr->g << endl;
5967 	      giac::gen gg(value._EQWptr->g);
5968 	      if (gg.is_symb_of_sommet(at_makevector))
5969 		gg=giac::eval(gg,1,contextptr);
5970 	      giac::sto(gg,g,contextptr);
5971 	    }
5972 	  }
5973 	}
5974 	continue;
5975       }
5976       if (key==KEY_CTRL_DEL){
5977 	vector<int> goto_sel;
5978 	if (xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gsel && xcas::do_select(*gsel,true,value) && value.type==_EQW){
5979 	  value=value._EQWptr->g;
5980 	  if (value.type==_SYMB){
5981 	    gen tmp=value._SYMBptr->feuille;
5982 	    if (tmp.type!=_VECT || tmp.subtype!=_SEQ__VECT){
5983 	      xcas::replace_selection(eq,tmp,gsel,&goto_sel,contextptr);
5984 	      continue;
5985 	    }
5986 	  }
5987 	  if (!goto_sel.empty() && gselparent && gselparent->type==_VECT && !gselparent->_VECTptr->empty()){
5988 	    vecteur & v=*gselparent->_VECTptr;
5989 	    if (v.back().type==_EQW){
5990 	      gen opg=v.back()._EQWptr->g;
5991 	      if (opg.type==_FUNC){
5992 		int i=0;
5993 		for (;i<v.size()-1;++i){
5994 		  if (&v[i]==gsel)
5995 		    break;
5996 		}
5997 		if (i<v.size()-1){
5998 		  if (v.size()==5 && (opg==at_integrate || opg==at_sum) && i>=2)
5999 		    v.erase(v.begin()+2,v.begin()+4);
6000 		  else
6001 		    v.erase(v.begin()+i);
6002 		  xcas::do_select(*gselparent,true,value);
6003 		  if (value.type==_EQW){
6004 		    value=value._EQWptr->g;
6005 		    // cout << goto_sel << " " << value << endl; continue;
6006 		    if (v.size()==2 && (opg==at_plus || opg==at_prod))
6007 		      value=protecteval(value,1,contextptr);
6008 		    goto_sel.erase(goto_sel.begin());
6009 		    xcas::replace_selection(eq,value,gselparent,&goto_sel,contextptr);
6010 		    continue;
6011 		  }
6012 		}
6013 	      }
6014 	    }
6015 	  }
6016 	}
6017       }
6018       if (key=='\\' || key==KEY_CTRL_F5){
6019 	xcas::do_select(eq.data,true,value);
6020 	if (value.type==_EQW)
6021 	  geq=value._EQWptr->g;
6022 	if (eq.attr.fontsize<=14)
6023 	  eq.attr.fontsize=18;
6024 	else
6025 	  eq.attr.fontsize=14;
6026 	redo=1;
6027       }
6028       if (key==KEY_CHAR_IMGNRY)
6029 	key='i';
6030       const char keybuf[2]={(key==KEY_CHAR_PMINUS?'-':char(key)),0};
6031       const char * adds=(key==KEY_CTRL_F4 || key==KEY_CHAR_PMINUS ||
6032 			 (key==char(key) && (isalphanum(key)|| key=='.' ))
6033 			 )?keybuf:keytostring(key,keyflag,contextptr);
6034       if (adds && !strcmp(adds,"VARS()"))
6035 	continue;
6036       translate_fkey(key);
6037       if ( key==KEY_CTRL_F1 || key==KEY_CTRL_F2 ||
6038 	   (key>=KEY_CTRL_F7 && key<=KEY_CTRL_F14)){
6039 	adds=console_menu(key,fmenu_cfg,1);//alph?"simplify":(keyflag==1?"factor":"partfrac");
6040 	// workaround for infinitiy
6041 	if (!adds) continue;
6042 	if (strlen(adds)>=2 && adds[0]=='o' && adds[1]=='o')
6043 	  key=KEY_CTRL_F3;
6044       }
6045       if (key==KEY_CTRL_F6 || key==KEY_CTRL_EXE){
6046 	adds= (key==KEY_CTRL_F6?"evalf":"eval");
6047       }
6048       if (key==KEY_CHAR_MINUS)
6049 	adds="-";
6050       if (key==KEY_CHAR_EQUAL)
6051 	adds="=";
6052       if (key==KEY_CHAR_RECIP)
6053 	adds="inv";
6054       if (key==KEY_CHAR_SQUARE)
6055 	adds="sq";
6056       if (key==KEY_CHAR_POWROOT)
6057 	adds="surd";
6058       if (key==KEY_CHAR_CUBEROOT)
6059 	adds="surd";
6060       if (key==KEY_CHAR_FACTOR)
6061 	adds="factor";
6062       if (key==KEY_CHAR_NORMAL)
6063 	adds="normal";
6064       int addssize=adds?strlen(adds):0;
6065       // cout << addssize << " " << adds << endl;
6066       if (0 && key==KEY_CTRL_EXE){
6067 	if (xcas::do_select(eq.data,true,value) && value.type==_EQW){
6068 	  //cout << "ok " << value._EQWptr->g << endl;
6069 	  DefineStatusMessage(((lang==1)?"resultat stocke dans last":"result stored in last"), 1, 0, 0);
6070 	  //DisplayStatusArea();
6071 	  giac::sto(value._EQWptr->g,giac::gen("last",contextptr),contextptr);
6072 	  return value._EQWptr->g;
6073 	}
6074 	//cout << "no " << eq.data << endl; if (value.type==_EQW) cout << value._EQWptr->g << endl ;
6075 	return geq;
6076       }
6077       if ( key!=KEY_CHAR_MINUS && key!=KEY_CHAR_EQUAL && key!=0 &&
6078 	   (ins || key==KEY_CHAR_PI || key==KEY_CTRL_VARS || key==KEY_CTRL_F3 || (addssize==1 && (isalphanum(adds[0])|| adds[0]=='.' || adds[0]=='-') ) )
6079 	   ){
6080 	edited=true;
6081 	if (line>=0 && xcas::eqw_select(eq.data,line,col,true,value)){
6082 	  string s;
6083 	  if (ins){
6084 	    if (key==KEY_CTRL_PASTE)
6085 	      s=paste_clipboard();
6086 	    else {
6087 	      if (value.type==_EQW){
6088 		s=value._EQWptr->g.print(contextptr);
6089 	      }
6090 	      else
6091 		s=value.print(contextptr);
6092 	    }
6093 	  }
6094 	  else
6095 	    s = adds;
6096 	  string msg("Line ");
6097 	  msg += print_INT_(line+1);
6098 	  msg += " Col ";
6099 	  msg += print_INT_(col+1);
6100 	  if (inputline(msg.c_str(),0,s,false,65,contextptr)==KEY_CTRL_EXE){
6101 	    value=gen(s,contextptr);
6102 	    if (col<0)
6103 	      (*geq._VECTptr)[line]=value;
6104 	    else
6105 	      (*((*geq._VECTptr)[line]._VECTptr))[col]=value;
6106 	    redo=2;
6107 	    key=KEY_SHIFT_RIGHT;
6108 	  }
6109 	  else
6110 	    continue;
6111 	}
6112 	else {
6113 	  vector<int> goto_sel;
6114 	  if (xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gsel && xcas::do_select(*gsel,true,value) && value.type==_EQW){
6115 	    string s;
6116 	    if (ins){
6117 	      if (key==KEY_CTRL_PASTE)
6118 		s=paste_clipboard();
6119 	      else {
6120 		s = value._EQWptr->g.print(contextptr);
6121 		if (key==KEY_CHAR_COMMA)
6122 		  s += ',';
6123 	      }
6124 	    }
6125 	    else
6126 	      s = adds;
6127 	    if (inputline(value._EQWptr->g.print(contextptr).c_str(),0,s,false)==KEY_CTRL_EXE){
6128 	      value=gen(s,contextptr);
6129 	      //cout << value << " goto " << goto_sel << endl;
6130 	      xcas::replace_selection(eq,value,gsel,&goto_sel,contextptr);
6131 	      firstrun=-1; // workaround, force 2 times display
6132 	    }
6133 	    continue;
6134 	  }
6135 	}
6136       }
6137       if (redo){
6138 	eq.data=0; // clear memory
6139 	eq.data=xcas::Equation_compute_size(geq,eq.attr,LCD_WIDTH_PX,contextptr);
6140 	eqdata=xcas::Equation_total_size(eq.data);
6141 	if (redo==1){
6142 	  dx=(eqdata.dx-LCD_WIDTH_PX)/2;
6143 	  dy=LCD_HEIGHT_PX-2*margin+eqdata.y;
6144 	  if (listormat) // select line l, col c
6145 	    xcas::eqw_select(eq.data,line,col,true,value);
6146 	  else {
6147 	    xcas::Equation_select(eq.data,true);
6148 	    xcas::eqw_select_down(eq.data);
6149 	  }
6150 	  continue;
6151 	}
6152       }
6153       bool doit=eqdata.dx>=LCD_WIDTH_PX;
6154       int delta=0;
6155       if (listormat){
6156 	if (key==KEY_CTRL_LEFT  || (!doit && key==KEY_SHIFT_LEFT)){
6157 	  if (line>=0 && xcas::eqw_select(eq.data,line,col,false,value)){
6158 	    if (col>=0){
6159 	      --col;
6160 	      if (col<0){
6161 		col=ncols-1;
6162 		if (line>0){
6163 		  --line;
6164 		  dy += value._EQWptr->dy+eq.attr.fontsize/2;
6165 		}
6166 	      }
6167 	    }
6168 	    else {
6169 	      if (line>0)
6170 		--line;
6171 	    }
6172 	    xcas::eqw_select(eq.data,line,col,true,value);
6173 	    if (doit) dx -= value._EQWptr->dx;
6174 	  }
6175 	  continue;
6176 	}
6177 	if (doit && key==KEY_SHIFT_LEFT){
6178 	  dx -= 20;
6179 	  continue;
6180 	}
6181 	if (key==KEY_CTRL_RIGHT  || (!doit && key==KEY_SHIFT_RIGHT)) {
6182 	  if (line>=0 && xcas::eqw_select(eq.data,line,col,false,value)){
6183 	    if (doit)
6184 	      dx += value._EQWptr->dx;
6185 	    if (col>=0){
6186 	      ++col;
6187 	      if (col==ncols){
6188 		col=0;
6189 		if (line<nlines-1){
6190 		  ++line;
6191 		  dy -= value._EQWptr->dy+eq.attr.fontsize/2;
6192 		}
6193 	      }
6194 	    } else {
6195 	      if (line<nlines-1)
6196 		++line;
6197 	    }
6198 	    xcas::eqw_select(eq.data,line,col,true,value);
6199 	  }
6200 	  continue;
6201 	}
6202 	if (key==KEY_SHIFT_RIGHT && doit){
6203 	  dx += 20;
6204 	  continue;
6205 	}
6206 	doit=eqdata.dy>=LCD_HEIGHT_PX-2*margin;
6207 	if (key==KEY_CTRL_UP || (!doit && key==KEY_CTRL_PAGEUP)){
6208 	  if (line>0 && col>=0 && xcas::eqw_select(eq.data,line,col,false,value)){
6209 	    --line;
6210 	    xcas::eqw_select(eq.data,line,col,true,value);
6211 	    if (doit)
6212 	      dy += value._EQWptr->dy+eq.attr.fontsize/2;
6213 	  }
6214 	  continue;
6215 	}
6216 	if (key==KEY_CTRL_PAGEUP && doit){
6217 	  dy += 10;
6218 	  continue;
6219 	}
6220 	if (key==KEY_CTRL_DOWN  || (!doit && key==KEY_CTRL_PAGEDOWN)){
6221 	  if (line<nlines-1 && col>=0 && xcas::eqw_select(eq.data,line,col,false,value)){
6222 	    if (doit)
6223 	      dy -= value._EQWptr->dy+eq.attr.fontsize/2;
6224 	    ++line;
6225 	    xcas::eqw_select(eq.data,line,col,true,value);
6226 	  }
6227 	  continue;
6228 	}
6229 	if ( key==KEY_CTRL_PAGEDOWN && doit){
6230 	  dy -= 10;
6231 	  continue;
6232 	}
6233       }
6234       else { // else listormat
6235 	if (key==KEY_CTRL_LEFT){
6236 	  delta=xcas::eqw_select_leftright(eq,true,alph?2:0,contextptr);
6237 	  // cout << "left " << delta << endl;
6238 	  if (doit) dx += (delta?delta:-20);
6239 	  continue;
6240 	}
6241 	if (key==KEY_SHIFT_LEFT){
6242 	  delta=xcas::eqw_select_leftright(eq,true,1,contextptr);
6243 	  vector<int> goto_sel;
6244 	  if (doit) dx += (delta?delta:-20);
6245 	  continue;
6246 	}
6247 	if (key==KEY_CTRL_RIGHT){
6248 	  delta=xcas::eqw_select_leftright(eq,false,alph?2:0,contextptr);
6249 	  // cout << "right " << delta << endl;
6250 	  if (doit)
6251 	    dx += (delta?delta:20);
6252 	  continue;
6253 	}
6254 	if (key==KEY_SHIFT_RIGHT){
6255 	  delta=xcas::eqw_select_leftright(eq,false,1,contextptr);
6256 	  // cout << "right " << delta << endl;
6257 	  if (doit)
6258 	    dx += (delta?delta:20);
6259 	  // dx=eqdata.dx-LCD_WIDTH_PX+20;
6260 	  continue;
6261 	}
6262 	doit=eqdata.dy>=LCD_HEIGHT_PX-2*margin;
6263 	if (key==KEY_CTRL_UP){
6264 	  delta=xcas::eqw_select_up(eq.data);
6265 	  // cout << "up " << delta << endl;
6266 	  continue;
6267 	}
6268 	//cout << "up " << eq.data << endl;
6269 	if (key==KEY_CTRL_PAGEUP && doit){
6270 	  dy=eqdata.y+eqdata.dy+20;
6271 	  continue;
6272 	}
6273 	if (key==KEY_CTRL_DOWN){
6274 	  delta=xcas::eqw_select_down(eq.data);
6275 	  // cout << "down " << delta << endl;
6276 	  continue;
6277 	}
6278 	//cout << "down " << eq.data << endl;
6279 	if ( key==KEY_CTRL_PAGEDOWN && doit){
6280 	  dy=eqdata.y+LCD_HEIGHT_PX-margin;
6281 	  continue;
6282 	}
6283       }
6284       if (adds){
6285 	edited=true;
6286 	if (strcmp(adds,"'")==0)
6287 	  adds="diff";
6288 	if (strcmp(adds,"^2")==0)
6289 	  adds="sq";
6290 	if (strcmp(adds,">")==0)
6291 	  adds="simplify";
6292 	if (strcmp(adds,"<")==0)
6293 	  adds="factor";
6294 	if (strcmp(adds,"#")==0)
6295 	  adds="partfrac";
6296 	string cmd(adds);
6297 	if (cmd.size() && cmd[cmd.size()-1]=='(')
6298 	  cmd ='\''+cmd.substr(0,cmd.size()-1)+'\'';
6299 	vector<int> goto_sel;
6300 	if (xcas::Equation_adjust_xy(eq.data,xleft,ytop,xright,ybottom,gsel,gselparent,gselpos,&goto_sel) && gsel){
6301 	  gen op;
6302 	  int addarg=0;
6303 	  if (addssize==1){
6304 	    switch (adds[0]){
6305 	    case '+':
6306 	      addarg=1;
6307 	      op=at_plus;
6308 	      break;
6309 	    case '^':
6310 	      addarg=1;
6311 	      op=at_pow;
6312 	      break;
6313 	    case '=':
6314 	      addarg=1;
6315 	      op=at_equal;
6316 	      break;
6317 	    case '-':
6318 	      addarg=1;
6319 	      op=at_binary_minus;
6320 	      break;
6321 	    case '*':
6322 	      addarg=1;
6323 	      op=at_prod;
6324 	      break;
6325 	    case '/':
6326 	      addarg=1;
6327 	      op=at_division;
6328 	      break;
6329 	    case '\'':
6330 	      addarg=1;
6331 	      op=at_derive;
6332 	      break;
6333 	    }
6334 	  }
6335 	  if (op==0)
6336 	    op=gen(cmd,contextptr);
6337 	  if (op.type==_SYMB)
6338 	    op=op._SYMBptr->sommet;
6339 	  // cout << "keyed " << adds << " " << op << " " << op.type << endl;
6340 	  if (op.type==_FUNC){
6341 	    edited=true;
6342 	    // execute command on selection
6343 	    gen tmp,value;
6344 	    if (xcas::do_select(*gsel,true,value) && value.type==_EQW){
6345 	      if (op==at_integrate || op==at_sum)
6346 		addarg=3;
6347 	      if (op==at_limit)
6348 		addarg=2;
6349 	      gen args=protecteval(value._EQWptr->g,1,contextptr);
6350 	      gen vx=xthetat?t__IDNT_e:x__IDNT_e;
6351 	      if (addarg==1)
6352 		args=makesequence(args,0);
6353 	      if (addarg==2)
6354 		args=makesequence(args,vx_var,0);
6355 	      if (addarg==3)
6356 		args=makesequence(args,vx_var,0,1);
6357 	      if (op==at_surd)
6358 		args=makesequence(args,key==KEY_CHAR_CUBEROOT?3:4);
6359 	      if (op==at_subst)
6360 		args=makesequence(args,giac::symb_equal(vx_var,0));
6361 	      unary_function_ptr immediate_op[]={*at_eval,*at_evalf,*at_evalc,*at_regrouper,*at_simplify,*at_normal,*at_ratnormal,*at_factor,*at_cfactor,*at_partfrac,*at_cpartfrac,*at_expand,*at_canonical_form,*at_exp2trig,*at_trig2exp,*at_sincos,*at_lin,*at_tlin,*at_tcollect,*at_texpand,*at_trigexpand,*at_trigcos,*at_trigsin,*at_trigtan,*at_halftan};
6362 	      if (equalposcomp(immediate_op,*op._FUNCptr)){
6363 		set_abort();
6364 		tmp=(*op._FUNCptr)(args,contextptr);
6365 		clear_abort();
6366 		esc_flag=0;
6367 		giac::ctrl_c=false;
6368 		kbd_interrupted=giac::interrupted=false;
6369 	      }
6370 	      else
6371 		tmp=symbolic(*op._FUNCptr,args);
6372 	      //cout << "sel " << value._EQWptr->g << " " << tmp << " " << goto_sel << endl;
6373 	      esc_flag=0;
6374 	      giac::ctrl_c=false;
6375 	      kbd_interrupted=giac::interrupted=false;
6376 	      if (!is_undef(tmp)){
6377 		xcas::replace_selection(eq,tmp,gsel,&goto_sel,contextptr);
6378 		if (addarg){
6379 		  xcas::eqw_select_down(eq.data);
6380 		  xcas::eqw_select_leftright(eq,false,0,contextptr);
6381 		}
6382 		eqdata=xcas::Equation_total_size(eq.data);
6383 		dx=(eqdata.dx-LCD_WIDTH_PX)/2;
6384 		dy=LCD_HEIGHT_PX-2*margin+eqdata.y;
6385 		firstrun=-1; // workaround, force 2 times display
6386 	      }
6387 	    }
6388 	  } // if (op.type==_FUNC)
6389 
6390 	} // if adjust_xy
6391       } // if (adds)
6392     }
6393     //*logptr(contextptr) << eq.data << endl;
6394   }
6395 
clear_turtle_history(GIAC_CONTEXT)6396   void clear_turtle_history(GIAC_CONTEXT){
6397     history_in(contextptr).clear();
6398     history_out(contextptr).clear();
6399     turtle_stack()=vector<logo_turtle>(1,logo_turtle());
6400   }
6401 
do_restart(GIAC_CONTEXT)6402   void do_restart(GIAC_CONTEXT){
6403     if (contextptr){
6404       if (contextptr->globalcontextptr && contextptr->globalcontextptr->tabptr)
6405 	contextptr->globalcontextptr->tabptr->clear();
6406     }
6407     else
6408       _restart(0,contextptr);
6409   }
do_run(const char * s,gen & g,gen & ge,const context * & contextptr)6410   void do_run(const char * s,gen & g,gen & ge,const context * & contextptr){
6411     warn_nr=os_shell=true;
6412     if (!contextptr)
6413       contextptr=new giac::context;
6414     if (!strcmp(s,"restart")){
6415       clear_turtle_history(contextptr);
6416       do_restart(contextptr);
6417       return;
6418     }
6419     int S=strlen(s);
6420     char buf[S+1];
6421     buf[S]=0;
6422     for (int i=0;i<S;++i){
6423       char c=s[i];
6424       if (c==0x1e || c==char(0x9c))
6425 	buf[i]='\n';
6426       else {
6427 	if (c==0x0d)
6428 	  buf[i]=' ';
6429 	else
6430 	  buf[i]=c;
6431       }
6432     }
6433     g=gen(buf,contextptr);
6434     //Console_Output(g.print(contextptr).c_str()); return ;
6435     giac::freeze=false;
6436     // execution_in_progress = 1;
6437     set_abort();
6438     ge=protecteval(equaltosto(g,contextptr),1,contextptr);
6439     clear_abort();
6440     // execution_in_progress = 0;
6441     if (esc_flag || ctrl_c){
6442       esc_flag=ctrl_c=interrupted=false;
6443       while (confirm("Interrupted","OK",true)==-1)
6444 	; // insure ON has been removed from keyboard buffer
6445       ge=string2gen("Interrupted",false);
6446       // memory full?
6447       if (!kbd_interrupted){
6448 	// clear turtle, display msg
6449 	clear_turtle_history(contextptr);
6450 	int res=confirm((lang==1)?"Memoire remplie! Purger":"Memory full. Purge",
6451 #ifdef NSPIRE_NEWLIB
6452 			(lang==1)?"enter: variable, esc: tout.":"enter: variables, esc: all",
6453 #else
6454 			(lang==1)?"EXE variable, Back: tout.":"EXE variables, Back: all",
6455 #endif
6456 			false);
6457 	if (res==KEY_CTRL_F1 && select_var(contextptr).type==_IDNT){
6458 	  size_t savestackptr = stackptr;
6459 #ifdef x86_64
6460 	  stackptr=0xffffffffffffffff;
6461 #else
6462 	  stackptr=0xffffffff;
6463 #endif
6464 	  _purge(g,contextptr);
6465 	  stackptr=savestackptr;
6466 	}
6467 	else
6468 	  do_restart(contextptr);
6469       }
6470     }
6471     //Console_Output("Done"); return ;
6472     esc_flag=0;
6473     giac::ctrl_c=false;
6474     giac::kbd_interrupted=giac::interrupted=false;
6475   }
6476 
6477 #ifdef NSPIRE_LED
6478 #include "kled.cc"
6479 #else
set_exam_mode(int i,GIAC_CONTEXT)6480   void set_exam_mode(int i,GIAC_CONTEXT){
6481     exam_mode=i;
6482   }
6483 #endif
print_duration(double & duration)6484   string print_duration(double & duration){
6485     if (duration<=0)
6486       return "";
6487     int s=std::floor(duration+.5);
6488     int h=s/3600;
6489     int m=((s+30)%3600)/60;
6490     char ch[6]="00h00";
6491     ch[0] += h/10;
6492     ch[1] += h%10;
6493     ch[3] += m/10;
6494     ch[4] += m%10;
6495     duration=h+m/100.0;
6496     return ch;
6497   }
islogo(const gen & g)6498   bool islogo(const gen & g){
6499     if (g.type!=_VECT || g._VECTptr->empty()) return false;
6500     if (g.subtype==_LOGO__VECT) return true;
6501     const vecteur & v=*g._VECTptr;
6502     if (islogo(v.back()))
6503       return true;
6504     for (size_t i=0;i<v.size();++i){
6505       if (v[i].type==_VECT && v[i].subtype==_LOGO__VECT)
6506 	return true;
6507     }
6508     return false;
6509   }
6510 
6511 
eqws(char * s,bool eval,GIAC_CONTEXT)6512   int eqws(char * s,bool eval,GIAC_CONTEXT){ // s buffer must be at least 512 char
6513     gen g,ge;
6514     int dconsole_save=dconsole_mode;
6515     int ss=strlen(s);
6516     for (int i=0;i<ss;++i){
6517       if (s[i]==char(0x9c))
6518 	s[i]='\n';
6519     }
6520     if (ss>=2 && (s[0]=='#' || s[0]=='"' ||
6521 		  (s[0]=='/' && (s[1]=='/' || s[1]=='*'))
6522 		  ))
6523       return textedit(s,giacmax(512,ss),contextptr);
6524     dconsole_mode=0;
6525     if (eval)
6526       do_run(s,g,ge,contextptr);
6527     else {
6528       if (s[0]==0)
6529 	ge=0;
6530       else
6531 	ge=gen(s,contextptr);
6532     }
6533     dconsole_mode=dconsole_save;
6534     if (is_undef(ge))
6535       return textedit(s,giacmax(512,ss),contextptr);
6536     if (ge.type==giac::_SYMB || (ge.type==giac::_VECT && !ge._VECTptr->empty() && !is_numericv(*ge._VECTptr)) ){
6537       if (islogo(ge)){
6538 	if (displaylogo()==KEY_SHUTDOWN)
6539 	  return KEY_SHUTDOWN;
6540 	return 0;
6541       }
6542       if (ispnt(ge)){
6543 	if (displaygraph(ge,contextptr)==KEY_SHUTDOWN)
6544 	  return KEY_SHUTDOWN;
6545 	// aborttimer = Timer_Install(0, check_execution_abort, 100); if (aborttimer > 0) { Timer_Start(aborttimer); }
6546 	return 0;
6547       }
6548       if (ge.is_symb_of_sommet(at_program))
6549 	return textedit(s,giacmax(ss,512),contextptr);
6550       if (taille(ge,256)>=256)
6551 	return 0;
6552     }
6553     gen tmp=eqw(ge,true,contextptr);
6554     if (is_undef(tmp) || tmp==ge || taille(ge,64)>=64)
6555       return 0;
6556     string S(tmp.print(contextptr));
6557     if (S.size()>=512)
6558       return 0;
6559     strcpy(s,S.c_str());
6560     return 1;
6561   }
6562 
6563 
6564 #define GIAC_TEXTAREA 1
6565 #if GIAC_TEXTAREA
6566   textArea * edptr=0;
6567 #ifdef SCROLLBAR
6568   typedef scrollbar TScrollbar;
6569 #endif
6570 
get_line_number(const char * msg1,const char * msg2)6571   int get_line_number(const char * msg1,const char * msg2){
6572     string s;
6573     int res=inputline(msg1,msg2,s,false);
6574     if (res==KEY_CTRL_EXIT)
6575       return 0;
6576     res=strtol(s.c_str(),0,10);
6577     return res;
6578   }
6579 
warn_python(int mode,bool autochange)6580   void warn_python(int mode,bool autochange){
6581     if (mode==0)
6582       confirm(autochange?((lang==1)?"Source en syntaxe Xcas detecte.":"Xcas syntax source code detected."):((lang==1)?"Syntaxe Xcas.":"Xcas syntax."),
6583 #ifdef NSPIRE_NEWLIB
6584 	      "enter: ok"
6585 #else
6586 	      "OK: ok"
6587 #endif
6588 	      );
6589     if (mode==1)
6590       if (autochange)
6591 	confirm((lang==1)?"Source en syntaxe Python. Passage":"Python syntax source detected. Setting",
6592 #ifdef NSPIRE_NEWLIB
6593 		(lang==1)?"en Python avec ^=**, enter: ok":"Python mode with ^=**, enter:ok"
6594 #else
6595 		(lang==1)?"en Python avec ^=**, OK: ok":"Python mode with ^=**, OK:ok"
6596 #endif
6597 		);
6598       else
6599 	confirm((lang==1)?"Syntaxe Python avec ^==**, tapez":"Python syntax with ^==**, type",
6600 #ifdef NSPIRE_NEWLIB
6601 		(lang==1)?"python_compat(2) pour xor. enter: ok":"python_compat(2) for xor. enter: ok"
6602 #else
6603 		(lang==1)?"python_compat(2) pour xor. OK: ok":"python_compat(2) for xor. OK: ok"
6604 #endif
6605 		);
6606     if (mode==2){
6607       confirm((lang==1)?"Syntaxe Python avec ^==xor":"Python syntax with ^==xor",
6608 #ifdef NSPIRE_NEWLIB
6609 	      (lang==1)?"python_compat(1) pour **. enter: ok":"python_compat(1) for **. enter: ok"
6610 #else
6611 	      (lang==1)?"python_compat(1) pour **. OK: ok":"python_compat(1) for **. OK: ok"
6612 #endif
6613 	      );
6614     }
6615     if (mode & 4){
6616       confirm((lang==1)?"Interpreteur MicroPython":"MicroPython interpreter",
6617 #ifdef NSPIRE_NEWLIB
6618 	      (lang==1)?"enter: ok":"enter: ok"
6619 #else
6620 	      (lang==1)?"OK: ok":"OK: ok"
6621 #endif
6622 	      );
6623     }
6624   }
6625 
check_do_graph(giac::gen & ge,int do_logo_graph_eqw,GIAC_CONTEXT)6626   int check_do_graph(giac::gen & ge,int do_logo_graph_eqw,GIAC_CONTEXT) {
6627     if (ge.type==giac::_SYMB || (ge.type==giac::_VECT && !ge._VECTptr->empty() && !is_numericv(*ge._VECTptr)) ){
6628       if (islogo(ge)){
6629 	if (do_logo_graph_eqw & 4){
6630 	  if (displaylogo()==KEY_SHUTDOWN)
6631 	    return KEY_SHUTDOWN;
6632 	}
6633 	return 0;
6634       }
6635       if (ispnt(ge)){
6636 	if (do_logo_graph_eqw & 2){
6637 	  if (displaygraph(ge,contextptr)==KEY_SHUTDOWN)
6638 	    return KEY_SHUTDOWN;
6639 	}
6640 	// aborttimer = Timer_Install(0, check_execution_abort, 100); if (aborttimer > 0) { Timer_Start(aborttimer); }
6641 	return 0;
6642       }
6643       if ( do_logo_graph_eqw % 2 ==0)
6644 	return 0;
6645       if (taille(ge,256)>=256 || ge.is_symb_of_sommet(at_program))
6646 	return 0; // sizeof(eqwdata)=44
6647       gen tmp=eqw(ge,false,contextptr);
6648       if (!is_undef(tmp) && tmp!=ge){
6649 	//dConsolePutChar(147);
6650 	*giac::logptr(contextptr) << ge.print(contextptr) << '\n';
6651 	ge=tmp;
6652       }
6653     }
6654     return 0;
6655   }
6656 
process_freeze()6657   void process_freeze(){
6658     if (freezeturtle){
6659       displaylogo();
6660       freezeturtle=false;
6661       return;
6662     }
6663     if (giac::freeze){
6664       giac::freeze=false;
6665 #ifdef NSPIRE_NEWLIB
6666       DefineStatusMessage((char*)((lang==1)?"Ecran fige. Taper esc":"Screen freezed. Press esc."), 1, 0, 0);
6667 #else
6668       DefineStatusMessage((char*)((lang==1)?"Ecran fige. Taper EXIT":"Screen freezed. Press EXIT."), 1, 0, 0);
6669 #endif
6670       DisplayStatusArea();
6671       for (;;){
6672 	int key;
6673 	GetKey(&key);
6674 	if (key==KEY_CTRL_EXIT)
6675 	  break;
6676       }
6677     }
6678   }
6679 
6680   // called from editor, return
check_parse(textArea * text,const std::vector<textElement> & v,int python,GIAC_CONTEXT)6681   int check_parse(textArea * text,const std::vector<textElement> & v,int python,GIAC_CONTEXT){
6682     if (v.empty())
6683       return 0;
6684     char status[256];
6685     for (int i=0;i<sizeof(status);++i)
6686       status[i]=0;
6687     int shift=0;
6688 #ifdef MICROPY_LIB
6689     if (xcas_python_eval==1){
6690 #if 0
6691       if (text->changed){
6692 	std::string tmp=text->filename;
6693 	tmp += (lang==1)?" a ete modifie!":" was modified!";
6694 	if (confirm(tmp.c_str(),
6695 #ifdef NSPIRE_NEWLIB
6696 		    (lang==1)?"enter: sauvegarder, esc: tant pis":"enter: save, esc: discard changes"
6697 #else
6698 		    (lang==1)?"OK: sauvegarder, Back: tant pis":"OK: save, Back: discard changes"
6699 #endif
6700 		    )==KEY_CTRL_F1){
6701 	  save_script(text->filename.c_str(),merge_area(text->elements));
6702 	  text->changed=false;
6703 	}
6704       }
6705       string tmp="from "+remove_extension(text->filename)+" import *"; // os error 2 ??
6706       micropy_eval(tmp.c_str());
6707 #else
6708       freezeturtle=false;
6709       // newlines do not work correctly unless we cut the input
6710       for (int i=0;i<=v.size();++i){
6711 	if (i==v.size() || (v[i].s.size() && v[i].s[0]!=' ')){
6712 	  string s=merge_area(vector<textElement>(v.begin()+shift,v.begin()+i));
6713 	  micropy_eval(s.c_str());
6714 	  if (parser_errorline>0){
6715 	    parser_errorline += shift;
6716 	    break;
6717 	  }
6718 	  shift=i;
6719 	}
6720       }
6721 #endif
6722       // should detect syntax errors here and return line number
6723       if (parser_errorline>0){
6724 	//--parser_errorline; // ?? something strange
6725 	sprintf(status,(lang==1)?"Erreur ligne %i (esc + d'info avec no de ligne decale de %i)":"Error line %i (esc more details with linenumber shifted by %i)",parser_errorline,shift);
6726       }
6727       else {
6728 	process_freeze();
6729 	sprintf(status,"%s",(lang==1)?"Syntaxe correcte":"Parse OK");
6730       }
6731       DefineStatusMessage(status,1,0,0);
6732       return parser_errorline;
6733     }
6734 #endif
6735     std::string s=merge_area(v);
6736     giac::python_compat(python,contextptr);
6737     if (python) s="@@"+s; // force Python translation
6738     freeze=true;
6739     giac::gen g(s,contextptr);
6740     freeze=false;
6741     int lineerr=giac::first_error_line(contextptr);
6742     if (lineerr){
6743       std::string tok=giac::error_token_name(contextptr);
6744       int pos=-1;
6745       if (lineerr>=1 && lineerr<=v.size()){
6746 	pos=v[lineerr-1].s.find(tok);
6747 	const std::string & err=v[lineerr-1].s;
6748 	if (pos>=err.size())
6749 	  pos=-1;
6750 	if (python){
6751 	  // find 1st token, check if it's def/if/elseif/for/while
6752 	  size_t i=0,j=0;
6753 	  for (;i<err.size();++i){
6754 	    if (err[i]!=' ')
6755 	      break;
6756 	  }
6757 	  std::string firsterr;
6758 	  for (j=i;j<err.size();++j){
6759 	    if (!isalpha(err[j]))
6760 	      break;
6761 	    firsterr += err[j];
6762 	  }
6763 	  // if there is no : at end set pos=-2
6764 	  if (firsterr=="for" || firsterr=="def" || firsterr=="if" || firsterr=="elseif" || firsterr=="while"){
6765 	    for (i=err.size()-1;i>0;--i){
6766 	      if (err[i]!=' ')
6767 		break;
6768 	    }
6769 	    if (err[i]!=':')
6770 	      pos=-2;
6771 	  }
6772 	}
6773       }
6774       else {
6775 	lineerr=v.size();
6776 	tok=(lang==1)?"la fin":"end";
6777 	pos=0;
6778       }
6779       if (pos>=0)
6780 	sprintf(status,(lang==1)?"Erreur ligne %i a %s":"Error line %i at %s",lineerr,tok.c_str());
6781       else
6782 	sprintf(status,(lang==1)?"Erreur ligne %i %s":"Error line %i %s",lineerr,(pos==-2?((lang==1)?", : manquant ?":", missing :?"):""));
6783       DefineStatusMessage(status,1,0,0);
6784     }
6785     else {
6786       set_abort();
6787       g=protecteval(g,1,contextptr);
6788       clear_abort();
6789       giac::ctrl_c=false;
6790       kbd_interrupted=giac::interrupted=false;
6791       // define the function
6792       if (check_do_graph(g,7,contextptr)==KEY_SHUTDOWN)
6793 	return KEY_SHUTDOWN;
6794       DefineStatusMessage((char *)((lang==1)?"Syntaxe correcte":"Parse OK"),1,0,0);
6795     }
6796     DisplayStatusArea();
6797     return lineerr;
6798   }
6799 
fix_newlines(textArea * edptr)6800   void fix_newlines(textArea * edptr){
6801     edptr->elements[0].newLine=0;
6802     for (size_t i=1;i<edptr->elements.size();++i){
6803       edptr->elements[i].newLine=1;
6804     }
6805   }
6806 
fix_mini(textArea * edptr)6807   void fix_mini(textArea * edptr){
6808     bool minimini=edptr->elements[0].minimini;
6809     for (size_t i=1;i<edptr->elements.size();++i){
6810       edptr->elements[i].minimini=minimini;
6811     }
6812   }
6813 
end_do_then(const std::string & s)6814   int end_do_then(const std::string & s){
6815     // skip spaces from end
6816     int l=s.size(),i,i0;
6817     const char * ptr=s.c_str();
6818     for (i=l-1;i>0;--i){
6819       if (ptr[i]!=' '){
6820 	if (ptr[i]==':' || ptr[i]=='{')
6821 	  return 1;
6822 	if (ptr[i]=='}')
6823 	  return -1;
6824 	break;
6825       }
6826     }
6827     if (i>0){
6828       for (i0=i;i0>=0;--i0){
6829 	if (!isalphanum(ptr[i0]) && ptr[i0]!=';' && ptr[i0]!=':')
6830 	  break;
6831       }
6832       if (i>i0+2){
6833 	if (ptr[i]==';')
6834 	  --i;
6835 	if (ptr[i]==':')
6836 	  --i;
6837       }
6838       std::string keyw(ptr+i0+1,ptr+i+1);
6839       const char * ptr=keyw.c_str();
6840       if (strcmp(ptr,"faire")==0 || strcmp(ptr,"do")==0 || strcmp(ptr,"alors")==0 || strcmp(ptr,"then")==0)
6841 	return 1;
6842       if (strcmp(ptr,"fsi")==0 || strcmp(ptr,"end")==0 || strcmp(ptr,"fi")==0 || strcmp(ptr,"od")==0 || strcmp(ptr,"ftantque")==0 || strcmp(ptr,"fpour")==0 || strcmp(ptr,"ffonction")==0 || strcmp(ptr,"ffunction")==0)
6843 	return -1;
6844     }
6845     return 0;
6846   }
6847 
add(textArea * edptr,const std::string & s)6848   void add(textArea *edptr,const std::string & s){
6849     int r=1;
6850     for (size_t i=0;i<s.size();++i){
6851       if (s[i]=='\n' || s[i]==char(0x9c))
6852 	++r;
6853     }
6854     edptr->elements.reserve(edptr->elements.size()+r);
6855     textElement cur;
6856     cur.lineSpacing=2;
6857     for (size_t i=0;i<s.size();++i){
6858       char c=s[i];
6859       if (c!='\n' && c!=char(0x9c)){
6860 	if (c!=char(0x0d))
6861 	  cur.s += c;
6862 	continue;
6863       }
6864       string tmp=string(cur.s.begin(),cur.s.end());
6865       cur.s.swap(tmp);
6866       edptr->elements.push_back(cur);
6867       ++edptr->line;
6868       cur.s="";
6869     }
6870     if (cur.s.size()){
6871       edptr->elements.push_back(cur);
6872       ++edptr->line;
6873     }
6874     fix_newlines(edptr);
6875   }
6876 
find_indentation(const std::string & s)6877   int find_indentation(const std::string & s){
6878     size_t indent=0;
6879     for (;indent<s.size();++indent){
6880       if (s[indent]!=' ')
6881 	break;
6882     }
6883     return indent;
6884   }
6885 
add_indented_line(std::vector<textElement> & v,int & textline,int & textpos)6886   void add_indented_line(std::vector<textElement> & v,int & textline,int & textpos){
6887     // add line
6888     v.insert(v.begin()+textline+1,v[textline]);
6889     std::string & s=v[textline].s;
6890     int indent=find_indentation(s);
6891     if (!s.empty())
6892       indent += 2*end_do_then(s);
6893     //cout << indent << s << ":" << endl;
6894     if (indent<0)
6895       indent=0;
6896     v[textline+1].s=std::string(indent,' ')+s.substr(textpos,s.size()-textpos);
6897     v[textline+1].newLine=1;
6898     v[textline].s=s.substr(0,textpos);
6899     ++textline;
6900     v[textline].nlines=1; // will be recomputed by cursor moves
6901     textpos=indent;
6902   }
6903 
undo(textArea * text)6904   void undo(textArea * text){
6905     if (text->undoelements.empty())
6906       return;
6907     giac::swapint(text->line,text->undoline);
6908     giac::swapint(text->pos,text->undopos);
6909     giac::swapint(text->clipline,text->undoclipline);
6910     giac::swapint(text->clippos,text->undoclippos);
6911     swap(text->elements,text->undoelements);
6912   }
6913 
set_undo(textArea * text)6914   void set_undo(textArea * text){
6915     text->changed=true;
6916     text->undoelements=text->elements;
6917     text->undopos=text->pos;
6918     text->undoline=text->line;
6919     text->undoclippos=text->clippos;
6920     text->undoclipline=text->clipline;
6921   }
6922 
add_nl(textArea * text,const std::string & ins)6923   void add_nl(textArea * text,const std::string & ins){
6924     std::vector<textElement> & v=text->elements;
6925     std::vector<textElement> w(v.begin()+text->line+1,v.end());
6926     v.erase(v.begin()+text->line+1,v.end());
6927     add(text,ins);
6928     for (size_t i=0;i<w.size();++i)
6929       v.push_back(w[i]);
6930     fix_newlines(text);
6931     text->changed=true;
6932   }
6933 
insert(textArea * text,const char * adds,bool indent)6934   void insert(textArea * text,const char * adds,bool indent){
6935     size_t n=strlen(adds),i=0;
6936     if (!n)
6937       return;
6938     set_undo(text);
6939     int l=text->line;
6940     if (l<0 || l>=text->elements.size())
6941       return; // invalid line number
6942     std::string & s=text->elements[l].s;
6943     int ss=int(s.size());
6944     int & pos=text->pos;
6945     if (pos>ss)
6946       pos=ss;
6947     std::string ins=s.substr(0,pos);
6948     for (;i<n;++i){
6949       if (adds[i]=='\n' || adds[i]==0x1e) {
6950 	break;
6951       }
6952       else {
6953 	if (adds[i]!=char(0x0d))
6954 	  ins += adds[i];
6955       }
6956     }
6957     if (i==n){ // no newline in inserted string
6958       s=ins+s.substr(pos,ss-pos);
6959       pos += n;
6960       return;
6961     }
6962     std::string S(adds+i+1);
6963     int decal=ss-pos;
6964     S += s.substr(pos,decal);
6965     // cout << S << " " << ins << endl;
6966     s=ins;
6967     if (indent){
6968       pos=s.size();
6969       int debut=0;
6970       for (i=0;i<S.size();++i){
6971 	if (S[i]=='\n' || S[i]==0x1e){
6972 	  add_indented_line(text->elements,text->line,pos);
6973 	  // cout << S.substr(debut,i-debut) << endl;
6974 	  text->elements[text->line].s += S.substr(debut,i-debut);
6975 	  pos = text->elements[text->line].s.size();
6976 	  debut=i+1;
6977 	}
6978       }
6979       //cout << S << " " << debut << " " << i << S.c_str()+debut << endl;
6980       add_indented_line(text->elements,text->line,pos);
6981       text->elements[text->line].s += (S.c_str()+debut);
6982       fix_newlines(text);
6983     }
6984     else
6985       add_nl(text,S);
6986     pos = text->elements[text->line].s.size()-decal;
6987     fix_mini(text);
6988   }
6989 
merge_area(const std::vector<textElement> & v)6990   std::string merge_area(const std::vector<textElement> & v){
6991     std::string s;
6992     size_t l=0;
6993     for (size_t i=0;i<v.size();++i)
6994       l += v[i].s.size()+1;
6995     s.reserve(l);
6996     for (size_t i=0;i<v.size();++i){
6997       s += v[i].s;
6998       s += '\n';
6999     }
7000     return s;
7001   }
7002 
isalphanum(char c)7003   bool isalphanum(char c){
7004     return isalpha(c) || (c>='0' && c<='9');
7005   }
7006 
search_msg()7007   void search_msg(){
7008 #ifdef NSPIRE_NEWLIB
7009     DefineStatusMessage((char *)((lang==1)?"enter: suivant, DEL: annuler":"enter: next, DEL: cancel"),1,0,0);
7010 #else
7011     DefineStatusMessage((char *)((lang==1)?"enter: suivant, DEL: annuler":"enter: next, DEL: cancel"),1,0,0);
7012 #endif
7013     DisplayStatusArea();
7014   }
7015 
7016 
show_status(textArea * text,const std::string & search,const std::string & replace)7017   void show_status(textArea * text,const std::string & search,const std::string & replace){
7018     if (text->editable && text->clipline>=0)
7019       DefineStatusMessage((char *)"PAD: select, COPY: copy, DEL: cut",1,0,0);
7020     else {
7021       std::string status;
7022 #ifdef GIAC_SHOWTIME
7023       int d=(int(millis()/60000) +time_shift) % (24*60); // minutes
7024       int heure=d/60;
7025       int minute=d%60;
7026       status += char('0'+heure/10);
7027       status += char('0'+(heure%10));
7028       status += ':';
7029       status += char('0'+(minute/10));
7030       status += char('0'+(minute%10));
7031 #endif
7032       if (text->editable){
7033 #ifndef NSPIRE_NEWLIB
7034 	status += (xthetat?" t":" x");
7035 #endif
7036 	if (text->python & 4)
7037 	  status += " MicroPython ";
7038 	else
7039 	  status += text->python?(text->python==2?" Py ^xor ":" Py ^=** "):" Xcas ";
7040 	status += giac::remove_extension(text->filename.c_str());
7041 	status += text->changed?" * ":" - ";
7042 	status += giac::printint(text->line+1);
7043 	status += '/';
7044 	status += giac::printint(text->elements.size());
7045       }
7046       if (search.size()){
7047 #ifdef NSPIRE_NEWLIB
7048 	status += " enter: " + search;
7049 #else
7050 	status += " EXE: " + search;
7051 #endif
7052 	if (replace.size())
7053 	  status += "->"+replace;
7054       }
7055       DefineStatusMessage((char *)status.c_str(), 1, 0, 0);
7056     }
7057     DisplayStatusArea();
7058   }
7059 
chk_replace(textArea * text,const std::string & search,const std::string & replace)7060   bool chk_replace(textArea * text,const std::string & search,const std::string & replace){
7061     if (replace.size()){
7062 #ifdef NSPIRE_NEWLIB
7063       DefineStatusMessage((char *)((lang==1)?"Remplacer? enter: Oui, 8 ou N: Non":"Replace? enter: Yes, 8 or N: No"),1,0,0);
7064 #else
7065       DefineStatusMessage((char *)((lang==1)?"Remplacer? EXE: Oui, 8 ou N: Non":"Replace? EXE: Yes, 8 or N: No"),1,0,0);
7066 #endif
7067     }
7068     else
7069       search_msg();
7070     DisplayStatusArea();
7071     for (;;){
7072       int key;
7073       GetKey(&key);
7074       if (key==KEY_CHAR_MINUS || key==KEY_CHAR_Y || key==KEY_CHAR_9 || key==KEY_CHAR_O || key==KEY_CTRL_EXE || key==KEY_CTRL_OK){
7075 	if (replace.size()){
7076 	  set_undo(text);
7077 	  std::string & s = text->elements[text->line].s;
7078 	  s=s.substr(0,text->pos-search.size())+replace+s.substr(text->pos,s.size()-text->pos);
7079 	  search_msg();
7080 	}
7081 	return true;
7082       }
7083       if (key==KEY_CTRL_DEL || (replace.empty() && key==KEY_CTRL_EXIT) || key==KEY_CTRL_LEFT || key==KEY_CTRL_RIGHT || key==KEY_CTRL_UP || key==KEY_CTRL_DOWN){
7084 	show_status(text,search,replace);
7085 	return false;
7086       }
7087       if (key==KEY_CHAR_8 || key==KEY_CHAR_N || key==KEY_CTRL_EXIT){
7088 	search_msg();
7089 	return true;
7090       }
7091     }
7092   }
7093 
check_leave(textArea * text)7094   int check_leave(textArea * text){
7095     if (text->editable && text->filename.size()){
7096       if (text->changed){
7097 	// save or cancel?
7098 	std::string tmp=text->filename;
7099 	if (strcmp(tmp.c_str(),"temp.py")==0){
7100 	  if (confirm((lang==1)?"Les modifications seront perdues":"Changes will be lost",
7101 #ifdef NSPIRE_NEWLIB
7102 		      (lang==1)?"enter: annuler, esc: tant pis":"enter: cancel, esc: confirm"
7103 #else
7104 		      (lang==1)?"OK: annuler, Back: tant pis":"OK: cancel, Back: confirm"
7105 #endif
7106 		      )==KEY_CTRL_F1)
7107 	    return 2;
7108 	  else {
7109 	    return 0;
7110 	  }
7111 	}
7112 	tmp += (lang==1)?" a ete modifie!":" was modified!";
7113 	if (confirm(tmp.c_str(),
7114 #ifdef NSPIRE_NEWLIB
7115 		    (lang==1)?"enter: sauvegarder, esc: tant pis":"enter: save, esc: discard changes"
7116 #else
7117 		    (lang==1)?"OK: sauvegarder, Back: tant pis":"OK: save, Back: discard changes"
7118 #endif
7119 		    )==KEY_CTRL_F1){
7120 	  save_script(text->filename.c_str(),merge_area(text->elements));
7121 	  text->changed=false;
7122 	  return 1;
7123 	}
7124 	return 0;
7125       }
7126       return 1;
7127     }
7128     return 0;
7129   }
7130 
print(int & X,int & Y,const char * buf,int color,bool revert,bool fake,bool minimini)7131   void print(int &X,int&Y,const char * buf,int color,bool revert,bool fake,bool minimini){
7132     if(minimini)
7133       X=PrintMiniMini(X, Y, buf, revert?4:0, color, COLOR_WHITE,fake);
7134     else
7135       X=PrintMini(X, Y, buf, revert?4:0, color, COLOR_WHITE, fake);
7136   }
7137 
match_print(char * singleword,int delta,int X,int Y,bool match,bool minimini)7138   void match_print(char * singleword,int delta,int X,int Y,bool match,bool minimini){
7139     // char buflog[128];sprintf(buflog,"%i %i %s               ",delta,(int)match,singleword);puts(buflog);
7140     char ch=singleword[delta];
7141     singleword[delta]=0;
7142     print(X,Y,singleword,0,false,/* fake*/true,minimini);
7143     singleword[delta]=ch;
7144     char buf[4];
7145     buf[0]=ch;
7146     buf[1]=0;
7147     // inverted print: colors are reverted too!
7148     int color;
7149     if (minimini)
7150       color=match?TEXT_COLOR_GREEN:TEXT_COLOR_RED;
7151     else
7152       color=match?COLOR_GREEN:COLOR_RED;
7153     print(X,Y,buf,color,true,/*fake*/false,minimini);
7154   }
7155 
match(textArea * text,int pos,int & line1,int & pos1,int & line2,int & pos2)7156   bool match(textArea * text,int pos,int & line1,int & pos1,int & line2,int & pos2){
7157     line2=-1;line1=-1;
7158     int linepos=text->line;
7159     const std::vector<textElement> & v=text->elements;
7160     if (linepos<0 || linepos>=v.size()) return false;
7161     const std::string * s=&v[linepos].s;
7162     int ss=s->size();
7163     if (pos<0 || pos>=ss) return false;
7164     char ch=(*s)[pos];
7165     int open1=0,open2=0,open3=0,inc=0;
7166     if (ch=='(' || ch=='['
7167 	|| ch=='{'
7168 	){
7169       line1=linepos;
7170       pos1=pos;
7171       inc=1;
7172     }
7173     if (
7174 	ch=='}' ||
7175 	ch==']' || ch==')'
7176 	){
7177       line2=linepos;
7178       pos2=pos;
7179       inc=-1;
7180     }
7181     if (!inc) return false;
7182     bool instring=false;
7183     for (;;){
7184       for (;pos>=0 && pos<ss;pos+=inc){
7185 	if ((*s)[pos]=='"' && (pos==0 || (*s)[pos-1]!='\\'))
7186 	  instring=!instring;
7187 	if (instring)
7188 	  continue;
7189 	switch ((*s)[pos]){
7190 	case '(':
7191 	  open1++;
7192 	  break;
7193 	case '[':
7194 	  open2++;
7195 	  break;
7196 	case '{':
7197 	  open3++;
7198 	  break;
7199 	case ')':
7200 	  open1--;
7201 	  break;
7202 	case ']':
7203 	  open2--;
7204 	  break;
7205 	case '}':
7206 	  open3--;
7207 	  break;
7208 	}
7209 	if (open1==0 && open2==0 && open3==0){
7210 	  //char buf[128];sprintf(buf,"%i %i",pos_orig,pos);puts(buf);
7211 	  if (inc>0){
7212 	    line2=linepos; pos2=pos;
7213 	  }
7214 	  else {
7215 	    line1=linepos; pos1=pos;
7216 	  }
7217 	  return true;
7218 	} // end if
7219       } // end for pos
7220       linepos+=inc;
7221       if (linepos<0 || linepos>=v.size())
7222 	return false;
7223       s=&v[linepos].s;
7224       ss=s->size();
7225       pos=inc>0?0:ss-1;
7226     } // end for linepos
7227     return false;
7228   }
7229 
get_selection(textArea * text,bool erase)7230   std::string get_selection(textArea * text,bool erase){
7231     int sel_line1,sel_line2,sel_pos1,sel_pos2;
7232     int clipline=text->clipline,clippos=text->clippos,textline=text->line,textpos=text->pos;
7233     if (clipline>=0){
7234       if (clipline<textline || (clipline==textline && clippos<textpos)){
7235 	sel_line1=clipline;
7236 	sel_line2=textline;
7237 	sel_pos1=clippos;
7238 	sel_pos2=textpos;
7239       }
7240       else {
7241 	sel_line1=textline;
7242 	sel_line2=clipline;
7243 	sel_pos1=textpos;
7244 	sel_pos2=clippos;
7245       }
7246     }
7247     std::string s(text->elements[sel_line1].s);
7248     if (erase){
7249       set_undo(text);
7250       text->line=sel_line1;
7251       text->pos=sel_pos1;
7252       text->elements[sel_line1].s=s.substr(0,sel_pos1)+text->elements[sel_line2].s.substr(sel_pos2,text->elements[sel_line2].s.size()-sel_pos2);
7253     }
7254     if (sel_line1==sel_line2){
7255       return s.substr(sel_pos1,sel_pos2-sel_pos1);
7256     }
7257     s=s.substr(sel_pos1,s.size()-sel_pos1)+'\n';
7258     int sel_line1_=sel_line1;
7259     for (sel_line1++;sel_line1<sel_line2;sel_line1++){
7260       s += text->elements[sel_line1].s;
7261       s += '\n';
7262     }
7263     s += text->elements[sel_line2].s.substr(0,sel_pos2);
7264     if (erase)
7265       text->elements.erase(text->elements.begin()+sel_line1_+1,text->elements.begin()+sel_line2+1);
7266     return s;
7267   }
7268 
change_mode(textArea * text,int flag,GIAC_CONTEXT)7269   void change_mode(textArea * text,int flag,GIAC_CONTEXT){
7270     if (bool(text->python)!=bool(flag)){
7271       text->python=flag;
7272       python_compat(text->python,contextptr);
7273       show_status(text,"","");
7274       warn_python(flag,true);
7275     }
7276   }
7277 
clearLine(int x,int y,color_t color=_WHITE)7278   void clearLine(int x, int y, color_t color=_WHITE) {
7279     // clear text line. x and y are text cursor coordinates
7280     // this is meant to achieve the same effect as using PrintXY with a line full of spaces (except it doesn't waste strings).
7281     int width=LCD_WIDTH_PX;
7282     if(x>1) width = 24*(21-x);
7283     drawRectangle((x-1)*18, y*24, width, 24, color);
7284   }
7285 
mPrintXY(int x,int y,char * msg,int mode,int color)7286   void mPrintXY(int x, int y, char*msg, int mode, int color) {
7287     char nmsg[50];
7288     nmsg[0] = 0x20;
7289     nmsg[1] = 0x20;
7290     nmsg[2] = '\0';
7291     strncat(nmsg, msg, 48);
7292     PrintXY(x, y, nmsg, mode ,color);
7293   }
7294 
drawScreenTitle(char * title,char * subtitle=0)7295   void drawScreenTitle(char* title, char* subtitle=0) {
7296     if(title != NULL) mPrintXY(1, 1, title, TEXT_MODE_NORMAL, TEXT_COLOR_BLUE);
7297     if(subtitle != NULL) mPrintXY(1, 2, subtitle, TEXT_MODE_NORMAL, TEXT_COLOR_BLACK);
7298   }
7299 
find_color(const char * s,GIAC_CONTEXT)7300   int find_color(const char * s,GIAC_CONTEXT){
7301     if (s[0]=='"')
7302       return 4;
7303     if (!isalpha(s[0]))
7304       return 0;
7305     char buf[256];
7306     const char * ptr=s;
7307     for (int i=0;i<255 && (isalphanum(*ptr) || *ptr=='_'); ++i){
7308       ++ptr;
7309     }
7310     strncpy(buf,s,ptr-s);
7311     buf[ptr-s]=0;
7312     if (strcmp(buf,"def")==0)
7313       return 1;
7314     //int pos=dichotomic_search(keywords,sizeof(keywords),buf);
7315     //if (pos>=0) return 1;
7316     gen g;
7317     int token=find_or_make_symbol(buf,g,0,false,contextptr);
7318     //*logptr(contextptr) << s << " " << buf << " " << token << " " << g << endl;
7319     if (token==T_UNARY_OP || token==T_UNARY_OP_38 || token==T_LOGO)
7320       return 3;
7321     if (token==T_NUMBER)
7322       return 2;
7323     if (token!=T_SYMBOL)
7324       return 1;
7325     return 0;
7326   }
7327 
strncasecmp_duplicate(const char * s1,const char * s2,size_t n)7328   int strncasecmp_duplicate(const char *s1, const char *s2, size_t n)
7329   {
7330     if (n != 0) {
7331       const unsigned char *us1 = (const unsigned char *)s1;
7332       const unsigned char *us2 = (const unsigned char *)s2;
7333 
7334       do {
7335 	if (tolower(*us1) != tolower(*us2++))
7336 	  return (tolower(*us1) - tolower(*--us2));
7337 	if (*us1++ == '\0')
7338 	  break;
7339       } while (--n != 0);
7340     }
7341     return (0);
7342   }
strcasestr_duplicate(const char * s,const char * find)7343   char *strcasestr_duplicate(const char *s, const char *find)
7344   {
7345     char c;
7346 
7347     if ((c = *find++) != 0) {
7348       c = tolower((unsigned char)c);
7349       size_t len = strlen(find);
7350       do {
7351 	char sc;
7352 	do {
7353 	  if ((sc = *s++) == 0)
7354 	    return (NULL);
7355 	} while ((char)tolower((unsigned char)sc) != c);
7356       } while (strncasecmp(s, find, len) != 0);
7357       s--;
7358     }
7359     return ((char *)s);
7360   }
7361 
7362 
7363   /* copy over the next token from an input string, WITHOUT
7364      skipping leading blanks. The token is terminated by the
7365      first appearance of tokchar, or by the end of the source
7366      string.
7367 
7368      The caller must supply sufficient space in token to
7369      receive any token, Otherwise tokens will be truncated.
7370 
7371      Returns: a pointer past the terminating tokchar.
7372 
7373      This will happily return an infinity of empty tokens if
7374      called with src pointing to the end of a string. Tokens
7375      will never include a copy of tokchar.
7376 
7377      A better name would be "strtkn", except that is reserved
7378      for the system namespace. Change to that at your risk.
7379 
7380      released to Public Domain, by C.B. Falconer.
7381      Published 2006-02-20. Attribution appreciated.
7382      Modified by gbl08ma not to skip blanks at the beginning.
7383   */
7384 
toksplit(const unsigned char * src,char tokchar,unsigned char * token,int lgh)7385   const unsigned char *toksplit(const unsigned char *src, /* Source of tokens */
7386 				char tokchar, /* token delimiting char */
7387 				unsigned char *token, /* receiver of parsed token */
7388 				int lgh) /* length token can receive */
7389   /* not including final '\0' */
7390   {
7391     if (src) {
7392       while (*src && (tokchar != *src)) {
7393 	if (lgh) {
7394 	  *token++ = *src;
7395 	  --lgh;
7396 	}
7397 	src++;
7398       }
7399       if (*src && (tokchar == *src)) src++;
7400     }
7401     *token = '\0';
7402     return src;
7403   } /* toksplit */
7404 
7405 
display(textArea * text,int & isFirstDraw,int & totalTextY,int & scroll,int & textY,GIAC_CONTEXT)7406   void display(textArea * text,int & isFirstDraw,int & totalTextY,int & scroll,int & textY,GIAC_CONTEXT){
7407 #ifdef CURSOR
7408     Cursor_SetFlashOff();
7409 #endif
7410     drawRectangle(text->x, text->y, LCD_WIDTH_PX, LCD_HEIGHT_PX-text->y, COLOR_WHITE);
7411     bool editable=text->editable;
7412     int showtitle = !editable && (text->title != NULL);
7413     std::vector<textElement> & v=text->elements;
7414     //drawRectangle(text->x, text->y+24, text->width, LCD_HEIGHT_PX-24, COLOR_WHITE);
7415     // insure cursor is visible
7416     if (editable && !isFirstDraw){
7417       int linesbefore=0,cur;
7418       for (cur=0;cur<text->line;++cur){
7419 	linesbefore += (v[cur].newLine+(v[cur].nlines-1))*(text->lineHeight+v[cur].lineSpacing); //*logptr(contextptr) << cur << "," << v[cur].nlines << " ";
7420       }
7421       // line begin Y is at scroll+linesbefore*17, must be positive
7422       if (linesbefore+scroll<0)
7423 	scroll = -linesbefore;
7424       linesbefore += (v[cur].newLine+(v[cur].nlines-1))*(text->lineHeight+v[cur].lineSpacing); //*logptr(contextptr) << '\n';
7425       // after line Y is at scroll+linesbefore*17
7426       if (linesbefore+scroll>148)
7427 	scroll = 148-linesbefore;
7428     }
7429     textY = scroll+(showtitle ? 24 : 0)+text->y; // 24 pixels for title (or not)
7430     int deltax=0;
7431     if (editable){
7432       if (v.size()<10){
7433 	deltax=9;
7434       }
7435       else {
7436 	if (v.size()<100)
7437 	  deltax=18;
7438 	else
7439 	  deltax=27;
7440       }
7441     }
7442     int & clipline=text->clipline;
7443     int & clippos=text->clippos;
7444     int & textline=text->line;
7445     int & textpos=text->pos;
7446     if (textline<0) textline=0;
7447     if (textline>=text->elements.size())
7448       textline=text->elements.size()-1;
7449     if (textpos<0) textpos=0;
7450     if (textpos>text->elements[textline].s.size())
7451       textpos=text->elements[textline].s.size();
7452     //char bufpos[512];  sprintf(bufpos,"%i,%i:%i,%i       ",textpos,textline,text->elements[textline].s.size(),text->elements.size());  puts(bufpos);
7453     if (clipline>=0){
7454       if (clipline>=v.size())
7455 	clipline=-1;
7456       else {
7457 	if (clippos<0)
7458 	  clippos=0;
7459 	if (clippos>=v[clipline].s.size())
7460 	  clippos=v[clipline].s.size()-1;
7461       }
7462     }
7463     int line1,line2,pos1=0,pos2=0;
7464     if (!match(text,text->pos,line1,pos1,line2,pos2) && line1==-1 && line2==-1)
7465       match(text,text->pos-1,line1,pos1,line2,pos2);
7466     //char bufpos[512];  sprintf(bufpos,"%i,%i:%i,%i       ",line1,pos1,line2,pos2);  puts(bufpos);
7467     for (int cur=0;cur < v.size();++cur) {
7468       const char* src = v[cur].s.c_str();
7469       if (cur==0){
7470 	int l=v[cur].s.size();
7471 	if (l>=1 && src[0]=='#')
7472 	  change_mode(text,1,contextptr); // text->python=true;
7473 	if (l>=2 && src[0]=='/' && src[1]=='/')
7474 	  change_mode(text,0,contextptr); // text->python=false;
7475 	if (l>=8 && src[0]=='f' && (src[1]=='o' || src[1]=='u') && src[2]=='n' && src[3]=='c' && src[4]=='t' && src[5]=='i' && src[6]=='o' && src[7]=='n')
7476 	  change_mode(text,0,contextptr); // text->python=false;
7477 	if (l>=4 && src[0]=='d' && src[1]=='e' && src[2]=='f' && src[3]==' ')
7478 	  change_mode(text,1,contextptr); // text->python=true;
7479 	//drawRectangle(text->x, text->y, text->width, LCD_HEIGHT_PX-(editable?17:0), COLOR_WHITE);
7480       }
7481       if (cur%4==0 && textY>=(showtitle?24:0))
7482 	waitforvblank();
7483       int textX=text->x,saveY=textY;
7484       if(v[cur].newLine) {
7485 	textY=textY+text->lineHeight+v[cur].lineSpacing;
7486       }
7487       if (!isFirstDraw && clipline==-1){
7488 	// check if we can skip directly to the next line
7489 	int y=textY+(v[cur].nlines-1)*(text->lineHeight+v[cur].lineSpacing);
7490 	if (y<-text->lineHeight){
7491 	  textY=y;
7492 	  continue;
7493 	}
7494       }
7495       int dh=18+v[cur].lineSpacing;
7496       if (textY+dh+(editable?17:0)>LCD_HEIGHT_PX){
7497 	if (isFirstDraw)
7498 	  dh -= textY+dh+(editable?17:0)-LCD_HEIGHT_PX;
7499 	else {
7500 	  textY = saveY;
7501 	  break;
7502 	}
7503       }
7504       //if (dh>0 && textY>=(showtitle?24:0))
7505       //drawRectangle(textX, textY, LCD_WIDTH_PX, dh, COLOR_WHITE);
7506       if (editable && textY>=(showtitle?24:0)){
7507 	char line_s[16];
7508 	sprint_int(line_s,cur+1);
7509 	os_draw_string_small(textX,textY,COLOR_MAGENTA,_WHITE,line_s);
7510       }
7511       textX=text->x+deltax;
7512       int tlen = v[cur].s.size();
7513       char singleword[tlen+32];
7514       // char* singleword = (char*)malloc(tlen+1); // because of this, a single text element can't have more bytes than malloc can provide
7515       if (cur==textline){
7516 	if (textpos<0 || textpos>tlen)
7517 	  textpos=tlen;
7518 	if (tlen==0 && text->editable){ // cursor on empty line
7519 	  drawRectangle(textX,textY,3,16,COLOR_BLACK);
7520 	}
7521       }
7522       bool chksel=false;
7523       int sel_line1,sel_line2,sel_pos1,sel_pos2;
7524       if (clipline>=0){
7525 	if (clipline<textline || (clipline==textline && clippos<textpos)){
7526 	  sel_line1=clipline;
7527 	  sel_line2=textline;
7528 	  sel_pos1=clippos;
7529 	  sel_pos2=textpos;
7530 	}
7531 	else {
7532 	  sel_line1=textline;
7533 	  sel_line2=clipline;
7534 	  sel_pos1=textpos;
7535 	  sel_pos2=clippos;
7536 	}
7537 	chksel=(sel_line1<=cur && cur<=sel_line2);
7538       }
7539       const char * match1=0; // matching parenthesis (or brackets?)
7540       const char * match2=0;
7541       if (cur==line1)
7542 	match1=v[cur].s.c_str()+pos1;
7543       else
7544 	match1=0;
7545       if (cur==line2)
7546 	match2=v[cur].s.c_str()+pos2;
7547       else
7548 	match2=0;
7549       // if (cur==textline && !match(v[cur].s.c_str(),textpos,match1,match2) && !match1 && !match2) match(v[cur].s.c_str(),textpos-1,match1,match2);
7550       // char buf[128];sprintf(buf,"%i %i %i        ",cur,(int)match1,(int)match2);puts(buf);
7551       const char * srcpos=src+textpos;
7552       bool minimini=v[cur].minimini;
7553       int couleur=v[cur].color;
7554       int nlines=1;
7555       bool linecomment=false;
7556       while (*src){
7557 	const char * oldsrc=src;
7558 	if ( (text->python && *src=='#') ||
7559 	     (!text->python && *src=='/' && *(src+1)=='/')){
7560 	  linecomment=true;
7561 	  couleur=4;
7562 	}
7563 	if (linecomment || !text->editable)
7564 	  src = (char*)toksplit((unsigned char*)src, ' ', (unsigned char*)singleword, minimini?50:35); //break into words; next word
7565 	else { // skip string (only with delimiters " ")
7566 	  if (*src=='"'){
7567 	    for (++src;*src;++src){
7568 	      if (*src=='"' && *(src-1)!='\\')
7569 		break;
7570 	    }
7571 	    if (*src=='"')
7572 	      ++src;
7573 	    int i=src-oldsrc;
7574 	    strncpy(singleword,oldsrc,i);
7575 	    singleword[i]=0;
7576 	  }
7577 	  else {
7578 	    size_t i=0;
7579 	    for (;*src==' ';++src){ // skip initial whitespaces
7580 	      ++i;
7581 	    }
7582 	    if (i==0){
7583 	      if (isalpha(*src)){ // skip keyword
7584 		for (;isalphanum(*src) || *src=='_';++src){
7585 		  ++i;
7586 		}
7587 	      }
7588 	      // go to next space or alphabetic char
7589 	      for (;*src;++i,++src){
7590 		if (*src==' ' || (i && *src>=' ' && *src<='/') || (text->python && *src=='#') || (!text->python && *src=='/' && *(src+1)=='/')|| *src=='"' || isalpha(*src))
7591 		  break;
7592 	      }
7593 	    }
7594 	    strncpy(singleword,oldsrc,i);
7595 	    singleword[i]=0;
7596 	    if (i==0){
7597 	      puts(src); // free(singleword);
7598 	      return ; // FIXME KEY_CTRL_F2;
7599 	    }
7600 	  } // end normal case
7601 	} // end else linecomment case
7602 	// take care of selection
7603 	bool invert=false;
7604 	if (chksel){
7605 	  if (cur<sel_line1 || cur>sel_line2)
7606 	    invert=false;
7607 	  else {
7608 	    int printpos1=oldsrc-v[cur].s.c_str();
7609 	    int printpos2=src-v[cur].s.c_str();
7610 	    if (cur==sel_line1 && printpos1<sel_pos1 && printpos2>sel_pos1){
7611 	      // cut word in 2 parts: first part not selected
7612 	      src=oldsrc+sel_pos1-printpos1;
7613 	      singleword[sel_pos1-printpos1]=0;
7614 	      printpos2=sel_pos1;
7615 	    }
7616 	    if (cur==sel_line2 && printpos1<sel_pos2 && printpos2>sel_pos2){
7617 	      src=oldsrc+sel_pos2-printpos1;
7618 	      singleword[sel_pos2-printpos1]=0;
7619 	      printpos2=sel_pos2;
7620 	    }
7621 	    // now singleword is totally unselected or totally selected
7622 	    // which one?
7623 	    if (cur==sel_line1){
7624 	      if (cur==sel_line2)
7625 		invert=printpos1>=sel_pos1 && printpos2<=sel_pos2;
7626 	      else
7627 		invert=printpos1>=sel_pos1;
7628 	    }
7629 	    else {
7630 	      if (cur==sel_line2)
7631 		invert=printpos2<=sel_pos2;
7632 	      else
7633 		invert=true;
7634 	    }
7635 	  }
7636 	}
7637 	//check if printing this word would go off the screen, with fake PrintMini drawing:
7638 	int temptextX = 0,temptextY=0;
7639 	print(temptextX,temptextY,singleword,couleur,false,/*fake*/true,minimini);
7640 	if(temptextX<text->width && temptextX + textX > text->width-6) {
7641 	  if (editable)
7642 	    textX=PrintMini(textX, textY, ">", 4, COLOR_MAGENTA, COLOR_WHITE);
7643 	  //time for a new line
7644 	  textX=text->x+deltax;
7645 	  textY=textY+text->lineHeight+v[cur].lineSpacing;
7646 	  //if (textY>=(showtitle?24:0))
7647 	  //  drawRectangle(0, textY, LCD_WIDTH_PX, 18+v[cur].lineSpacing, COLOR_WHITE);
7648 	  ++nlines;
7649 	} //else still fits, print new word normally (or just increment textX, if we are not "on stage" yet)
7650 	if(textY >= (showtitle?24:0) && textY < LCD_HEIGHT_PX) {
7651 	  temptextX=textX;
7652 	  if (editable){
7653 	    couleur=linecomment?5:find_color(singleword,contextptr);
7654 	    if (couleur==1) couleur=COLOR_BLUE;
7655 	    if (couleur==2) couleur=COLOR_YELLOWDARK;
7656 	    if (couleur==3) couleur=33024;
7657 	    if (couleur==4) couleur=COLOR_MAGENTA;
7658 	    if (couleur==5) couleur=COLOR_GREEN;
7659 	    //char ch[32];
7660 	    //sprint_int(ch,couleur);
7661 	    //puts(singleword); puts(ch);
7662 	  }
7663 	  if (linecomment || !text->editable || singleword[0]=='"')
7664 	    print(textX,textY,singleword,couleur,invert,/*fake*/false,minimini);
7665 	  else { // print two parts, commandname in color and remain in black
7666 	    char * ptr=singleword;
7667 	    if (isalpha(*ptr)){
7668 	      while (isalphanum(*ptr) || *ptr=='_')
7669 		++ptr;
7670 	    }
7671 	    char ch=*ptr;
7672 	    *ptr=0;
7673 	    print(textX,textY,singleword,couleur,invert,/*fake*/false,minimini);
7674 	    *ptr=ch;
7675 	    print(textX,textY,ptr,COLOR_BLACK,invert,/*fake*/false,minimini);
7676 	  }
7677 	  // ?add a space removed from token
7678 	  if( ((linecomment || !text->editable)?*src:*src==' ') || v[cur].spaceAtEnd){
7679 	    if (*src==' ')
7680 	      ++src;
7681 	    print(textX,textY," ",COLOR_BLACK,invert,false,minimini);
7682 	  }
7683 	  // ?print cursor, and par. matching
7684 	  if (editable){
7685 	    if (match1 && oldsrc<=match1 && match1<src)
7686 	      match_print(singleword,match1-oldsrc,temptextX,textY,
7687 			  line2!=-1,
7688 			  // match2,
7689 			  minimini);
7690 	    if (match2 && oldsrc<=match2 && match2<src)
7691 	      match_print(singleword,match2-oldsrc,temptextX,textY,
7692 			  line1!=-1,
7693 			  //match1,
7694 			  minimini);
7695 	  }
7696 	  if (editable && cur==textline){
7697 	    if (oldsrc<=srcpos && (srcpos<src || (srcpos==src && textpos==tlen))){
7698 	      if (textpos>=2 && v[cur].s[textpos-1]==' ' && v[cur].s[textpos-2]!=' ' && srcpos-oldsrc==strlen(singleword)+1){ // fix cursor position after space
7699 		//char ch[512];
7700 		//sprintf(ch,"%s %i %i %i %i",singleword,strlen(singleword),srcpos-oldsrc,textpos,v[cur].s[textpos-2]);
7701 		//puts(ch);
7702 		singleword[srcpos-oldsrc-1]=' ';
7703 	      }
7704 	      singleword[srcpos-oldsrc]=0;
7705 	      print(temptextX,temptextY,singleword,couleur,false,/*fake*/true,minimini);
7706 	      //drawLine(temptextX, textY+14, temptextX, textY-14, COLOR_BLACK);
7707 	      //drawLine(temptextX+1, textY+14, temptextX+1, textY-14, COLOR_BLACK);
7708 	      drawRectangle(temptextX-1,textY,3,16,COLOR_BLACK);
7709 	    }
7710 	  }
7711 	} // end if testY visible
7712 	else {
7713 	  textX += temptextX;
7714 	  if(*src || v[cur].spaceAtEnd) textX += 7; // size of a PrintMini space
7715 	}
7716       } // end while (*src)
7717       // free(singleword);
7718       v[cur].nlines=nlines; //if (cur<6) *logptr(contextptr) << cur << ":" << src << nlines << '\n';
7719       if (isFirstDraw)
7720 	totalTextY = textY+(showtitle ? 0 : 24);
7721     } // end main draw loop (for cur<v.size())
7722     int dh=LCD_HEIGHT_PX-textY-text->lineHeight-(editable?17:0);
7723     if (dh>0)
7724       drawRectangle(0, textY+text->lineHeight, LCD_WIDTH_PX, dh, COLOR_WHITE);
7725     isFirstDraw=0;
7726     if(showtitle) {
7727       waitforvblank();
7728       drawRectangle(0, 0, LCD_WIDTH_PX, 24, _WHITE);
7729       drawScreenTitle((char*)text->title);
7730     }
7731     //if (editable)
7732     if (editable){
7733       // waitforvblank();
7734       drawRectangle(0,205,LCD_WIDTH_PX,17,44444);
7735       PrintMiniMini(0,205,text->python?"shift-1 test|2 loop|3 undo|4 misc|5 +-|6 logo|7 lin|8 list|9plot":"shift-1 test|2 loop|3 undo|4 misc|5 +-|6 logo|7 matr|8 list",4,44444,giac::_BLACK);
7736       //draw_menu(1);
7737     }
7738 #ifdef SCROLLBAR
7739     int scrollableHeight = LCD_HEIGHT_PX-24*(showtitle ? 2 : 1)-text->y;
7740     //draw a scrollbar:
7741     if(text->scrollbar) {
7742       TScrollbar sb;
7743       sb.I1 = 0;
7744       sb.I5 = 0;
7745       sb.indicatormaximum = totalTextY;
7746       sb.indicatorheight = scrollableHeight;
7747       sb.indicatorpos = -scroll;
7748       sb.barheight = scrollableHeight;
7749       sb.bartop = (showtitle ? 24 : 0)+text->y;
7750       sb.barleft = text->width - 6;
7751       sb.barwidth = 6;
7752 
7753       Scrollbar(&sb);
7754     }
7755 #endif
7756   }
7757 
move_to_word(textArea * text,const std::string & s,const std::string & replace,int & isFirstDraw,int & totalTextY,int & scroll,int & textY,GIAC_CONTEXT)7758   bool move_to_word(textArea * text,const std::string & s,const std::string & replace,int & isFirstDraw,int & totalTextY,int & scroll,int & textY,GIAC_CONTEXT){
7759     if (!s.size())
7760       return false;
7761     int line=text->line,pos=text->pos;
7762     if (line>=text->elements.size())
7763       line=0;
7764     if (pos>=text->elements[line].s.size())
7765       pos=0;
7766     for (;line<text->elements.size();++line){
7767       int p=text->elements[line].s.find(s,pos);
7768       if (p>=0 && p<text->elements[line].s.size()){
7769 	text->line=line;
7770 	text->clipline=line;
7771 	text->clippos=p;
7772 	text->pos=p+s.size();
7773 	display(text,isFirstDraw,totalTextY,scroll,textY,contextptr); // this modifies text->elements[].nlines (no idea why), 2 calls insure scrolling is adequate
7774 	display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
7775 	text->clipline=-1;
7776 	return chk_replace(text,s,replace);
7777       }
7778       pos=0;
7779     }
7780     for (line=0;line<text->line;++line){
7781       int p=text->elements[line].s.find(s,0);
7782       if (p>=0 && p<text->elements[line].s.size()){
7783 	text->line=line;
7784 	text->clipline=line;
7785 	text->clippos=p;
7786 	text->pos=p+s.size();
7787 	display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
7788 	display(text,isFirstDraw,totalTextY,scroll,textY,contextptr); // 2 callslike above
7789 	text->clipline=-1;
7790 	return chk_replace(text,s,replace);
7791       }
7792     }
7793     return false;
7794   }
7795 
load_script(const char * filename,std::string & s)7796   int load_script(const char * filename,std::string & s){
7797     const char * ch =read_file(filename);
7798     s=ch?ch:"";
7799     return 1;
7800   }
7801 
save_script(const char * filename,const string & s)7802   void save_script(const char * filename,const string & s){
7803 #ifdef NUMWORKS
7804     char buf[s.size()+2];
7805     buf[0]=1;
7806     strcpy(buf+1,s.c_str());
7807 #else
7808     char buf[s.size()+1];
7809     strcpy(buf,s.c_str());
7810 #endif
7811 #ifdef NSPIRE_NEWLIB
7812     char filenametns[strlen(filename)+5];
7813     strcpy(filenametns,filename);
7814     strcpy(filenametns+strlen(filename),".tns");
7815     write_file(filenametns,buf);
7816 #else
7817     write_file(filename,buf);
7818 #endif
7819   }
7820 
textedit(char * s,int bufsize,bool OKparse,const giac::context * contextptr)7821   bool textedit(char * s,int bufsize,bool OKparse,const giac::context * contextptr){
7822     if (!s)
7823       return false;
7824     int ss=strlen(s);
7825     if (ss==0){
7826       *s=' ';
7827       s[1]=0;
7828       ss=1;
7829     }
7830     textArea ta;
7831     ta.elements.clear();
7832     ta.editable=true;
7833     ta.clipline=-1;
7834     ta.changed=false;
7835     ta.filename="temp.py";
7836     ta.y=0;
7837     ta.python=true;
7838     ta.allowEXE=false;//true; // set back to true later
7839     ta.OKparse=OKparse;
7840     bool str=s[0]=='"' && s[ss-1]=='"';
7841     if (str){
7842       s[ss-1]=0;
7843       add(&ta,s+1);
7844     }
7845     else
7846       add(&ta,s);
7847     ta.line=0;
7848     ta.pos=ta.elements[ta.line].s.size();
7849     int res=doTextArea(&ta,contextptr);
7850     drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE);
7851     os_hide_graph();
7852     if (res==TEXTAREA_RETURN_EXIT)
7853       return false;
7854     string S(merge_area(ta.elements));
7855     if (str)
7856       S='"'+S+'"';
7857     int Ssize=S.size();
7858     if (Ssize<bufsize){
7859       strcpy(s,S.c_str());
7860       for (--Ssize;Ssize>=0;--Ssize){
7861 	if ((unsigned char)s[Ssize]==0x9c || s[Ssize]=='\n')
7862 	  s[Ssize]=0;
7863 	if (s[Ssize]!=' ')
7864 	  break;
7865       }
7866       return true;
7867     }
7868     return false;
7869   }
7870 
textedit(char * s,int bufsize,const giac::context * contextptr)7871   bool textedit(char * s,int bufsize,const giac::context * contextptr){
7872     return textedit(s,bufsize,false,contextptr);
7873   }
7874 
7875 #if 0
7876   int get_filename(char * filename,const char * extension){
7877     return 0;
7878   }
7879 #else
get_filename(char * filename,const char * extension)7880   int get_filename(char * filename,const char * extension){
7881     handle_f5();
7882     string str;
7883 #ifdef NSPIRE_NEWLIB
7884     int res=inputline((lang==1)?"esc ou chaine vide: annulation":"esc or empty string: cancel",(lang==1)?"Nom de fichier:":"Filename:",str,false);
7885 #else
7886     int res=inputline((lang==1)?"EXIT ou chaine vide: annulation":"EXIT or empty string: cancel",(lang==1)?"Nom de fichier:":"Filename:",str,false);
7887 #endif
7888     if (res==KEY_CTRL_EXIT || str.empty())
7889       return 0;
7890     strcpy(filename,str.c_str());
7891     int s=strlen(filename);
7892     if (strcmp(filename+s-3,extension))
7893       strcpy(filename+s,extension);
7894     // if file already exists, warn, otherwise create
7895     if (!file_exists(filename))
7896       return 1;
7897     if (confirm((lang==1)?"  Le fichier existe!":"  File exists!",
7898 #ifdef NSPIRE_NEWLIB
7899 		(lang==1)?"enter: ecraser, esc: annuler":"enter:overwrite, esc: cancel"
7900 #else
7901 		(lang==1)?"OK: ecraser,Back: annuler":"OK:overwrite, Back: cancel"
7902 #endif
7903 		)==KEY_CTRL_F1)
7904       return 1;
7905     return 0;
7906   }
7907 #endif
7908 
input_matrix(const gen & g,gen & ge,GIAC_CONTEXT)7909   const char * input_matrix(const gen &g,gen & ge,GIAC_CONTEXT){
7910 #ifdef MICROPY_LIB
7911     if (xcas_python_eval==1){
7912       if (ge.type==_VECT)
7913 	ge.subtype=0;
7914       static string input_matrix_s=g.print(contextptr)+'='+ge.print(contextptr);
7915       return input_matrix_s.c_str();
7916     }
7917 #endif
7918     if (ge.type==giac::_VECT)
7919       sto(ge,g,contextptr);
7920     return "";
7921   }
7922 
input_matrix(bool list,GIAC_CONTEXT)7923   const char * input_matrix(bool list,GIAC_CONTEXT){
7924     static std::string * sptr=0;
7925     if (!sptr)
7926       sptr=new std::string;
7927     *sptr="";
7928     giac::gen v(giac::_VARS(0,contextptr));
7929     giac::vecteur w;
7930     if (v.type==giac::_VECT){
7931       for (size_t i=0;i<v._VECTptr->size();++i){
7932 	giac::gen & tmp = (*v._VECTptr)[i];
7933 	if (tmp.type==giac::_IDNT){
7934 	  giac::gen tmpe(protecteval(tmp,1,contextptr));
7935 	  if (list){
7936 	    if (tmpe.type==giac::_VECT && !ckmatrix(tmpe))
7937 	      w.push_back(tmp);
7938 	  }
7939 	  else {
7940 	    if (ckmatrix(tmpe))
7941 	      w.push_back(tmp);
7942 	  }
7943 	}
7944       }
7945     }
7946     std::string msg;
7947     if (w.empty())
7948       msg=(lang==1)?(list?"Creer nouvelle liste":"Creer nouvelle matrice"):(list?"Create new list":"Create new matrix");
7949     else
7950       msg=(((lang==1)?"Creer nouveau ou editer ":"Create new or edit ")+(w.size()==1?w.front():giac::gen(w,giac::_SEQ__VECT)).print(contextptr));
7951     handle_f5();
7952     if (inputline(msg.c_str(),((lang==1)?"Nom de variable:":"Variable name:"),*sptr,false) && !sptr->empty() && isalpha((*sptr)[0])){
7953       giac::gen g(*sptr,contextptr);
7954       giac::gen ge(protecteval(g,1,contextptr));
7955       if (g.type==giac::_IDNT){
7956 	if (ge.type==giac::_VECT){
7957 	  ge=eqw(ge,true,contextptr);
7958 	  ge=protecteval(ge,1,contextptr);
7959 	  return input_matrix(g,ge,contextptr);
7960 	  if (ge.type==giac::_VECT)
7961 	    sto(ge,g,contextptr);
7962 	  else
7963 	    cout << "edited " << ge << endl;
7964 	  return ""; // return sptr->c_str();
7965 	}
7966 	if (ge==g || confirm_overwrite()){
7967 	  *sptr="";
7968 	  if (inputline(((lang==1)?(list?"Nombre d'elements":"Nombre de lignes"):(list?"Elements number":"Line number")),"",*sptr,true)){
7969 	    int l=strtol(sptr->c_str(),0,10);
7970 	    if (l>0 && l<256){
7971 	      int c;
7972 	      if (list)
7973 		c=0;
7974 	      else {
7975 		std::string tmp(*sptr+((lang==1)?" lignes.":" lines."));
7976 		*sptr="";
7977 		inputline(tmp.c_str(),(lang==1)?"Colonnes:":"Columns:",*sptr,true);
7978 		c=strtol(sptr->c_str(),0,10);
7979 	      }
7980 	      if (c==0){
7981 		ge=giac::vecteur(l);
7982 	      }
7983 	      else {
7984 		if (c>0 && l*c<256)
7985 		  ge=giac::_matrix(giac::makesequence(l,c),contextptr);
7986 	      }
7987 	      ge=eqw(ge,true,contextptr);
7988 	      ge=protecteval(ge,1,contextptr);
7989 	      return input_matrix(g,ge,contextptr);
7990 	    } // l<256
7991 	  }
7992 	} // ge==g || overwrite confirmed
7993       } // g.type==_IDNT
7994       else {
7995 	invalid_varname();
7996       }
7997     } // isalpha
7998     return 0;
7999   }
8000 
get_searchitem(std::string & replace)8001   std::string get_searchitem(std::string & replace){
8002     replace="";
8003     std::string search;
8004     handle_f5();
8005 #ifdef NSPIRE_NEWLIB
8006     int res=inputline((lang==1)?"esc ou chaine vide: annulation":"esc or empty string: cancel",(lang==1)?"Chercher:":"Search:",search,false);
8007     if (search.empty() || res==KEY_CTRL_EXIT)
8008       return "";
8009     replace="";
8010     std::string tmp=((lang==1)?"esc: recherche seule de ":"esc: search only ")+search;
8011 #else
8012     int res=inputline((lang==1)?"EXIT ou chaine vide: annulation":"EXIT or empty string: cancel",(lang==1)?"Chercher:":"Search:",search,false);
8013     if (search.empty() || res==KEY_CTRL_EXIT)
8014       return "";
8015     replace="";
8016     std::string tmp=((lang==1)?"EXIT: recherche seule de ":"EXIT: search only ")+search;
8017 #endif
8018     handle_f5();
8019     res=inputline(tmp.c_str(),(lang==1)?"Remplacer par:":"Replace by:",replace,false);
8020     if (res==KEY_CTRL_EXIT)
8021       replace="";
8022     return search;
8023   }
8024 
doTextArea(textArea * text,GIAC_CONTEXT)8025   int doTextArea(textArea* text,GIAC_CONTEXT) {
8026     int scroll = 0;
8027     int isFirstDraw = 1;
8028     int totalTextY = 0,textY=0;
8029     bool editable=text->editable;
8030     int showtitle = !editable && (text->title != NULL);
8031     int scrollableHeight = LCD_HEIGHT_PX-24*(showtitle ? 2 : 1)-text->y;
8032     std::vector<textElement> & v=text->elements;
8033     std::string search,replace;
8034     show_status(text,search,replace);
8035     if (text->line>=v.size())
8036       text->line=0;
8037     display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8038     while(1) {
8039       if (text->line>=v.size())
8040 	text->line=0;
8041       display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8042       if(text->type == TEXTAREATYPE_INSTANT_RETURN) return 0;
8043       int keyflag = GetSetupSetting( (unsigned int)0x14);
8044       int key;
8045       GetKey(&key);
8046       if (key==KEY_SHUTDOWN)
8047 	return key;
8048       if (key==KEY_CTRL_F3) // Numworks has no UNDO key
8049 	key=KEY_CTRL_UNDO;
8050 #if 1
8051       if (key == KEY_CTRL_SETUP) {
8052 	menu_setup(contextptr);
8053 	continue;
8054       }
8055 #endif
8056       if (key!=KEY_CTRL_PRGM && key!=KEY_CHAR_FRAC)
8057 	translate_fkey(key);
8058       //char keylog[32];sprint_int(keylog,key); puts(keylog);
8059       show_status(text,search,replace);
8060       int & clipline=text->clipline;
8061       int & clippos=text->clippos;
8062       int & textline=text->line;
8063       int & textpos=text->pos;
8064       if (key==KEY_CTRL_CUT && clipline<0) // if no selection, CUT -> pixel menu
8065 	key=KEY_CTRL_F3;
8066       if (!editable && (key==KEY_CHAR_ANS || key==KEY_BOOK || key=='\t' || key==KEY_CTRL_EXE))
8067 	return key;
8068       if (editable){
8069 	if (key=='\t'){
8070 	  int indent=0; // indent deduced from prev line
8071 	  if (textline!=0){
8072 	    std::string & s=v[textline-1].s;
8073 	    indent=find_indentation(s);
8074 	    if (!s.empty())
8075 	      indent+=2*end_do_then(s);
8076 	  }
8077 	  std::string & s=v[textline].s;
8078 	  int curindent=find_indentation(s);
8079 	  int diff=curindent-indent;
8080 	  if (diff>0){
8081 	    s=s.substr(diff,s.size()-diff);
8082 	    if (textpos>diff)
8083 	      textpos -= diff;
8084 	    else
8085 	      textpos = 0;
8086 	    continue;
8087 	  }
8088 	  if (diff<0){
8089 	    s=string(-diff,' ')+s;
8090 	    textpos += -diff;
8091 	    continue;
8092 	  }
8093 	  key=KEY_BOOK;
8094 	}
8095 	if (key==KEY_BOOK){
8096 	  string curs=v[textline].s.substr(0,textpos);
8097 	  if (!curs.empty()){
8098 	    string adds=help_insert(curs.c_str(),contextptr);
8099 	    if (!adds.empty())
8100 	      insert(text,adds.c_str(),false);
8101 	  }
8102 	  continue;
8103 	}
8104 	if (key==KEY_CHAR_FRAC && clipline<0){
8105 	  if (textline==0) continue;
8106 	  std::string & s=v[textline].s;
8107 	  std::string & prev_s=v[textline-1].s;
8108 	  int indent=find_indentation(s),prev_indent=find_indentation(prev_s);
8109 	  if (!prev_s.empty())
8110 	    prev_indent += 2*end_do_then(prev_s);
8111 	  int diff=indent-prev_indent;
8112 	  if (diff>0 && diff<=s.size())
8113 	    s=s.substr(diff,s.size()-diff);
8114 	  if (diff<0)
8115 	    s=string(-diff,' ')+s;
8116 	  textpos -= diff;
8117 	  continue;
8118 	}
8119 	if (key==KEY_CTRL_VARS){
8120 	  displaylogo();
8121 	  continue;
8122 	}
8123 	if (0 && key==KEY_CHAR_ANS){ // lack of keys, ANS -> menu
8124 	  int err=check_parse(text,v,text->python,contextptr);
8125 	  if (err==KEY_SHUTDOWN)
8126 	    return err;
8127 	  if (err) // move cursor to the error line
8128 	    textline=err-1;
8129 	  continue;
8130 	}
8131 	if (key>=KEY_SELECT_LEFT && key<=KEY_SELECT_RIGHT){
8132 	  if (clipline<0){
8133 	    clipline=textline;
8134 	    clippos=textpos;
8135 	    show_status(text,search,replace);
8136 	  }
8137 	  if (key==KEY_SELECT_LEFT){
8138 	    if (textpos)
8139 	      --textpos;
8140 	    else {
8141 	      if (textline){
8142 		--textline;
8143 		textpos=v[textline].s.size();
8144 	      }
8145 	    }
8146 	  }
8147 	  if (key==KEY_SELECT_RIGHT){
8148 	    if (textpos<v[textline].s.size())
8149 	      ++textpos;
8150 	    else {
8151 	      if (textline<v.size()){
8152 		++textline;
8153 		textpos=0;
8154 	      }
8155 	    }
8156 	  }
8157 	  if (key==KEY_SELECT_UP){
8158 	    if (textline){
8159 	      --textline;
8160 	      textpos=giacmin(textpos,v[textline].s.size());
8161 	    }
8162 	  }
8163 	  if (key==KEY_SELECT_DOWN){
8164 	    if (textline<v.size()){
8165 	      ++textline;
8166 	      textpos=giacmin(textpos,v[textline].s.size());
8167 	    }
8168 	  }
8169 	}
8170 	if (key==KEY_CTRL_CLIP) {
8171 #if 1
8172 	  if (clipline>=0){
8173 	    copy_clipboard(get_selection(text,false),true);
8174 	    clipline=-1;
8175 	  }
8176 	  else {
8177 	    clipline=textline;
8178 	    clippos=textpos;
8179 	    show_status(text,search,replace);
8180 	  }
8181 #else
8182 	  copy_clipboard(v[textline].s,false);
8183 	  DefineStatusMessage((char*)"Line copied to clipboard", 1, 0, 0);
8184 	  DisplayStatusArea();
8185 #endif
8186 	  continue;
8187 	}
8188 	if (key==KEY_CTRL_F5){
8189 	  bool minimini=!v[0].minimini;
8190 	  for (int i=0;i<v.size();++i)
8191 	    v[i].minimini=minimini;
8192 	  text->lineHeight=minimini?13:17;
8193 	  isFirstDraw=1;
8194 	  display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8195 	  continue;
8196 	}
8197 	if (clipline<0){
8198 	  const char * adds;
8199 #if 1
8200 	  if ( (key>=KEY_CTRL_F1 && key<=KEY_CTRL_F4) ||
8201 	       (key >= KEY_CTRL_F6 && key <= KEY_CTRL_F14)
8202 	       ){
8203 	    string le_menu=text->python?
8204 	      "F1 test\nif \nelse \n<\n>\n==\n!=\n&&\n||\nF2 loop\nfor \nfor in\nrange(\nwhile \nbreak\ndef\nreturn \n#\nF4 misc\n:\n;\n_\n!\n%\nfrom  import *\nprint(\ninput(\nF6 tortue\nforward(\nbackward(\nleft(\nright(\npencolor(\ncircle(\nreset()\nfrom turtle import *\nF9 plot\nplot(\ntext(\narrow(\nlinear_regression_plot(\nscatter(\naxis(\nbar(\nfrom matplotl import *\nF7 linalg\nadd(\nsub(\nmul(\ninv(\ndet(\nrref(\ntranspose(\nfrom linalg import *\nF: color\nred\nblue\ngreen\ncyan\nyellow\nmagenta\nblack\nwhite\nF= draw\nset_pixel(\ndraw_line(\ndraw_rectangle(\nfill_rect(\ndraw_polygon(\ndraw_circle(\ndraw_string(\nfrom graphic import *\nF> cplx\nabs(\narg(\nre(\nim(\nconj(\npolar(\nrect(\nfrom cmath import *\n":
8205 	      "F1 test\nif \nelse \n<\n>\n==\n!=\nand\nor\nF2 loop\nfor \nfor in\nrange(\nwhile \nbreak\nf(x):=\nreturn \nlocal\nF4 misc\n;\n:\n_\n!\n%\n&\nprint(\ninput(\nF6 tortue\navance\nrecule\ntourne_gauche\ntourne_droite\nrond\ndisque\nrepete\nefface\nF7 lin\nmatrix(\ndet(\nmatpow(\nranm(\nrref(\ntran(\negvl(\negv(\nF: arit\n mod \nirem(\nifactor(\ngcd(\nisprime(\nnextprime(\npowmod(\niegcd(\nF9 plot\nplot(\nplotseq(\nplotlist(\nplotparam(\nplotpolar(\nplotfield(\nhistogram(\nbarplot(\nF= misc\n<\n>\n_\n!\n % \nrand(\nbinomial(\nnormald(\nF> cplx\nabs(\narg(\nre(\nim(\nconj(\ncsolve(\ncfactor(\ncpartfrac(\n";
8206 	    le_menu += "F8 list\nmakelist(\nrange(\nseq(\nlen(\nappend(\nranv(\nsort(\napply(\nF; real\nexact(\napprox(\nfloor(\nceil(\nround(\nsign(\nmax(\nmin(\nF< prog\n;\n:\n\\\n&\n?\n!\ndebug(\npython(\n";
8207 	    const char * ptr=console_menu(key,(char*)(le_menu.c_str()),2);
8208 	    if (!ptr){
8209 	      show_status(text,search,replace);
8210 	      continue;
8211 	    }
8212 	    adds=ptr;
8213 	  }
8214 	  else
8215 #endif
8216 	    adds=keytostring(key,keyflag,text->python,contextptr);
8217 	  if (key!=KEY_CHAR_ANS && adds){
8218 	    bool isex=adds[0]=='\n';
8219 	    if (isex)
8220 	      ++adds;
8221 	    bool isif=strcmp(adds,"if ")==0,
8222 	      iselse=strcmp(adds,"else ")==0,
8223 	      isfor=strcmp(adds,"for ")==0,
8224 	      isforin=strcmp(adds,"for in")==0,
8225 	      isdef=strcmp(adds,"f(x):=")==0 || strcmp(adds,"def")==0,
8226 	      iswhile=strcmp(adds,"while ")==0,
8227 	      islist=strcmp(adds,"list ")==0,
8228 	      ismat=strcmp(adds,"matrix ")==0;
8229 	    if (islist){
8230 	      input_matrix(true,contextptr);
8231 	      continue;
8232 	    }
8233 	    if (ismat){
8234 	      input_matrix(false,contextptr);
8235 	      continue;
8236 	    }
8237 	    if (text->python){
8238 	      if (isif)
8239 		adds=isex?"if x<0:\nx=-x":"if :\n";
8240 	      if (iselse)
8241 		adds="else:\n";
8242 	      if (isfor)
8243 		adds=isex?"for j in range(10):\nprint(j*j)":"for  in range():\n";
8244 	      if (isforin)
8245 		adds=isex?"for j in [1,4,9,16]:\nprint(j)":"for  in :\n";
8246 	      if (iswhile && isex)
8247 		adds="a,b=25,15\nwhile b!=0:\na,b=b,a%b";
8248 	      if (isdef)
8249 		adds=isex?"def f(x):\nreturn x*x*x\n":"def f(x):\n\nreturn\n";
8250 	    } else {
8251 	      if (isif)
8252 		adds=(lang==1)?(isex?"si x<0 alors x:=-x; fsi;":"si  alors\n\nsinon\n\nfsi;"):(isex?"if x<0 then x:=-x; fi;":"if  then\n\nelse\n\nfi;");
8253 	      if (lang && iselse)
8254 		adds="sinon ";
8255 	      if (isfor)
8256 		adds=(lang==1)?(isex?"pour j de 1 jusque 10 faire\nprint(j*j);\nfpour;":"pour  de  jusque  faire\n\nfpour;"):(isex?"for j from 1 to 10 do\nprint(j*j);\nod;":"for  from  to  do\n\nod;");
8257 	      if (isforin)
8258 		adds=(lang==1)?(isex?"pour j in [1,4,9,16] faire\nprint(j)\nfpour;":"pour  in  faire\n\nfpour;"):(isex?"for j in [1,4,9,16] do\nprint(j);od;":"for  in  do\n\nod;");
8259 	      if (iswhile)
8260 		adds=(lang==1)?(isex?"a,b:=25,15;\ntantque b!=0 faire\na,b:=b,irem(a,b);\nftantque;a;":"tantque  faire\n\nftantque;"):(isex?"a,b:=25,15;\nwhile b!=0 do\na,b:=b,irem(a,b);\nod;a;":"while  do\n\nod;");
8261 	      if (isdef)
8262 		adds=(lang==1)?(isex?"fonction f(x)\nlocal j;\nj:=x*x;\nreturn j;\nffonction:;\n":"fonction f(x)\nlocal j;\n\nreturn ;\nffonction:;"):(isex?"function f(x)\nlocal j;\nj:=x*x;\nreturn j;\nffunction:;\n":"function f(x)\n  local j;\n\n return ;\nffunction:;");
8263 	    }
8264 	    insert(text,adds,key!=KEY_CTRL_PASTE); // was true, but we should not indent when pasting
8265 	    show_status(text,search,replace);
8266 	    continue;
8267 	  }
8268 	}
8269       }
8270       textElement * ptr=& v[textline];
8271       const int interligne=16;
8272       switch(key){
8273       case KEY_CTRL_DEL:
8274 	if (clipline>=0){
8275 	  copy_clipboard(get_selection(text,true),true);
8276 	  // erase selection
8277 	  clipline=-1;
8278 	}
8279 	else {
8280 	  if (editable){
8281 	    if (textpos){
8282 	      set_undo(text);
8283 	      std::string & s=v[textline].s;
8284 	      int nextpos=textpos-1;
8285 	      if (textpos==find_indentation(s)){
8286 		for (int line=textline-1;line>=0;--line){
8287 		  int ind=find_indentation(v[line].s);
8288 		  if (textpos>ind){
8289 		    nextpos=ind;
8290 		    break;
8291 		  }
8292 		}
8293 	      }
8294 	      s.erase(s.begin()+nextpos,s.begin()+textpos);
8295 	      textpos=nextpos;
8296 	    }
8297 	    else {
8298 	      if (textline){
8299 		set_undo(text);
8300 		--textline;
8301 		textpos=v[textline].s.size();
8302 		v[textline].s += v[textline+1].s;
8303 		v[textline].nlines += v[textline+1].nlines;
8304 		v.erase(v.begin()+textline+1);
8305 	      }
8306 	    }
8307 	  }
8308 	  show_status(text,search,replace);
8309 	}
8310 	break;
8311       case KEY_CTRL_S:
8312 	display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8313 	search=get_searchitem(replace);
8314 	if (!search.empty()){
8315 	  for (;;){
8316 	    if (!move_to_word(text,search,replace,isFirstDraw,totalTextY,scroll,textY,contextptr)){
8317 	      break;
8318 	    }
8319 	  }
8320 	  show_status(text,search,replace);
8321 	}
8322 	continue;
8323       case KEY_CTRL_OK:
8324 	if (text->allowEXE || !text->editable) return TEXTAREA_RETURN_EXE;
8325 	if (search.size()){
8326 	  for (;;){
8327 	    if (!move_to_word(text,search,replace,isFirstDraw,totalTextY,scroll,textY,contextptr))
8328 	      break;
8329 	  }
8330 	  show_status(text,search,replace);
8331 	  continue;
8332 	}
8333 	else {
8334           if (!text->OKparse) return TEXTAREA_RETURN_EXE;
8335 	  int err=check_parse(text,v,text->python,contextptr);
8336 	  if (err==KEY_SHUTDOWN)
8337 	    return err;
8338 	  if (err) // move cursor to the error line
8339 	    textline=err-1;
8340 	  continue;
8341 	}
8342 	break;
8343       case KEY_CTRL_EXE:
8344 	if (search.size()){
8345 	  for (;;){
8346 	    if (!move_to_word(text,search,replace,isFirstDraw,totalTextY,scroll,textY,contextptr))
8347 	      break;
8348 	  }
8349 	  show_status(text,search,replace);
8350 	  continue;
8351 	}
8352 	if (clipline<0 && editable){
8353 	  set_undo(text);
8354 	  add_indented_line(v,textline,textpos);
8355 	  show_status(text,search,replace);
8356 	}
8357 	break;
8358       case KEY_CTRL_UNDO:
8359 	undo(text);
8360 	break;
8361       case KEY_SHIFT_LEFT:
8362 	textpos=0;
8363 	break;
8364       case KEY_SHIFT_RIGHT:
8365 	textpos=v[textline].s.size();
8366 	break;
8367       case KEY_CTRL_LEFT:
8368 	if (editable){
8369 	  --textpos;
8370 	  if (textpos<0){
8371 	    if (textline==0)
8372 	      textpos=0;
8373 	    else {
8374 	      --textline;
8375 	      show_status(text,search,replace);
8376 	      textpos=v[textline].s.size();
8377 	    }
8378 	  }
8379 	  if (textpos>=0)
8380 	    break;
8381 	}
8382       case KEY_CTRL_UP:
8383 	if (editable){
8384 	  if (textline>0){
8385 	    --textline;
8386 	    show_status(text,search,replace);
8387 	  }
8388 	  else {
8389 	    textline=0;
8390 	    textpos=0;
8391 	  }
8392 	} else {
8393 	  if (scroll < 0) {
8394 	    scroll = scroll + interligne;
8395 	    if(scroll > 0) scroll = 0;
8396 	  }
8397 	}
8398 	break;
8399       case KEY_CTRL_RIGHT:
8400 	++textpos;
8401 	if (textpos<=ptr->s.size())
8402 	  break;
8403 	if (textline==v.size()-1){
8404 	  textpos=ptr->s.size();
8405 	  break;
8406 	}
8407 	textpos=0;
8408       case KEY_CTRL_DOWN:
8409 	if (editable){
8410 	  if (textline<v.size()-1)
8411 	    ++textline;
8412 	  else {
8413 	    textline=v.size()-1;
8414 	    textpos=v[textline].s.size();
8415 	  }
8416 	  show_status(text,search,replace);
8417 	}
8418 	else {
8419 	  if (textY > scrollableHeight-(showtitle ? 0 : interligne)) {
8420 	    scroll = scroll - interligne;
8421 	    if(scroll < -totalTextY+scrollableHeight-(showtitle ? 0 : interligne)) scroll = -totalTextY+scrollableHeight-(showtitle ? 0 : interligne);
8422 	  }
8423 	}
8424 	break;
8425       case KEY_CTRL_PAGEDOWN:
8426 	if (editable){
8427 	  textline=v.size()-1;
8428 	  textpos=v[textline].s.size();
8429 	}
8430 	else {
8431 	  if (textY > scrollableHeight-(showtitle ? 0 : interligne)) {
8432 	    scroll = scroll - scrollableHeight;
8433 	    if(scroll < -totalTextY+scrollableHeight-(showtitle ? 0 : interligne)) scroll = -totalTextY+scrollableHeight-(showtitle ? 0 : interligne);
8434 	  }
8435 	}
8436 	break;
8437       case KEY_CTRL_PAGEUP:
8438 	if (editable)
8439 	  textline=0;
8440 	else {
8441 	  if (scroll < 0) {
8442 	    scroll = scroll + scrollableHeight;
8443 	    if(scroll > 0) scroll = 0;
8444 	  }
8445 	}
8446 	break;
8447       case KEY_SAVE:
8448 	save_script(text->filename.c_str(),merge_area(v));
8449 	text->changed=false;
8450 	char status[256];
8451 	sprintf(status,(lang==1)?"%s sauvegarde":"%s saved",text->filename.c_str());
8452 	DefineStatusMessage(status, 1, 0, 0);
8453 	DisplayStatusArea();
8454 	continue;
8455       case KEY_CTRL_F1:
8456 	if(text->allowF1) return KEY_CTRL_F1;
8457 	break;
8458       case KEY_CTRL_MENU: case KEY_CTRL_F6:
8459 	// case KEY_CHAR_ANS:
8460 	if (!text->editable) 	return TEXTAREA_RETURN_EXIT;
8461 	if (clipline<0 && text->editable && text->filename.size()){
8462 	  Menu smallmenu;
8463 	  smallmenu.numitems=12;
8464 	  MenuItem smallmenuitems[smallmenu.numitems];
8465 	  smallmenu.items=smallmenuitems;
8466 	  smallmenu.height=12;
8467 	  smallmenu.scrollbar=0;
8468 	  //smallmenu.title = "KhiCAS";
8469 	  smallmenuitems[0].text = (char*)((lang==1)?"Tester syntaxe":"Check syntax");
8470 	  smallmenuitems[1].text = (char*)((lang==1)?"Sauvegarder":"Save");
8471 	  smallmenuitems[2].text = (char*)((lang==1)?"Sauvegarder comme":"Save as");
8472 	  if (exam_mode) smallmenuitems[2].text = (char*)"";
8473 	  smallmenuitems[3].text = (char*)((lang==1)?"Inserer":"Insert");
8474 	  smallmenuitems[4].text = (char*)((lang==1)?"Effacer":"Clear");
8475 	  smallmenuitems[5].text = (char*)((lang==1)?"Chercher,remplacer":"Search, replace");
8476 	  smallmenuitems[6].text = (char*)((lang==1)?"Aller a la ligne":"Goto line");
8477 	  int p=python_compat(contextptr);
8478 	  if (p&4)
8479 	    smallmenuitems[7].text = (char*)"Change syntax (MicroPython)";
8480 	  else {
8481 	    if (p==0)
8482 	      smallmenuitems[7].text = (char*)"Change syntax (Xcas)";
8483 	    if (p==1)
8484 	      smallmenuitems[7].text = (char*)"Change syntax (Xcas comp Python ^=**)";
8485 	    if (p==2)
8486 	      smallmenuitems[7].text = (char*)"Change syntax (Xcas comp Python ^=xor)";
8487 	  }
8488 	  smallmenuitems[8].text = (char *)((lang==1)?"Changer taille caracteres":"Change fontsize");
8489 	  smallmenuitems[9].text = (char *)aide_khicas_string;
8490 	  smallmenuitems[10].text = (char *)((lang==1)?"A propos":"About");
8491 	  smallmenuitems[11].text = (char*)((lang==1)?"Quitter":"Quit");
8492 	  int sres = doMenu(&smallmenu);
8493 	  if(sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) {
8494 	    sres=smallmenu.selection;
8495 	    if (sres==12){
8496 	      int res=check_leave(text);
8497 	      if (res==2)
8498 		continue;
8499 	      return TEXTAREA_RETURN_EXIT;
8500 	    }
8501 	    if(sres >= 10) {
8502 	      textArea text;
8503 	      text.editable=false;
8504 	      text.clipline=-1;
8505 	      text.title = smallmenuitems[sres-1].text;
8506 	      add(&text,smallmenu.selection==10?((lang==1)?shortcuts_fr_string:shortcuts_en_string):((lang==1)?apropos_fr_string:apropos_en_string));
8507 	      if (doTextArea(&text,contextptr)==KEY_SHUTDOWN)
8508 		return KEY_SHUTDOWN;
8509 	      continue;
8510 	    }
8511 	    if (sres==9 && editable){
8512 	      bool minimini=!v[0].minimini;
8513 	      for (int i=0;i<v.size();++i)
8514 		v[i].minimini=minimini;
8515 	      text->lineHeight=minimini?13:17;
8516 	      continue;
8517 	    }
8518 	    if (sres==1){
8519 	      int err=check_parse(text,v,text->python,contextptr);
8520 	      if (err==KEY_SHUTDOWN)
8521 		return err;
8522 	      if (err) // move cursor to the error line
8523 		textline=err-1;
8524 	    }
8525 	    if (sres==3 && exam_mode==0){
8526 	      char filename[MAX_FILENAME_SIZE+1];
8527 	      if (get_filename(filename,".py")){
8528 		text->filename=filename;
8529 		sres=2;
8530 	      }
8531 	    }
8532 	    if(sres == 2) {
8533 	      save_script(text->filename.c_str(),merge_area(v));
8534 	      text->changed=false;
8535 	      char status[256];
8536 	      sprintf(status,(lang==1)?"%s sauvegarde":"%s saved",text->filename.c_str());
8537 	      DefineStatusMessage(status, 1, 0, 0);
8538 	      DisplayStatusArea();
8539 	    }
8540 	    if (sres==4){
8541 	      char filename[MAX_FILENAME_SIZE+1];
8542 	      std::string ins;
8543 	      if (giac_filebrowser(filename, "py", "Scripts") && load_script(filename,ins))
8544 		insert(text,ins.c_str(),false);//add_nl(text,ins);
8545 	    }
8546 	    if (sres==5){
8547 	      std::string s(merge_area(v));
8548 #if 0
8549 	      for (size_t i=0;i<s.size();++i){
8550 		if (s[i]=='\n')
8551 		  s[i]=0x1e;
8552 	      }
8553 	      CLIP_Store(s.c_str(),s.size()+1);
8554 #endif
8555 	      copy_clipboard(s,false);
8556 	      set_undo(text);
8557 	      v.resize(1);
8558 	      v[0].s="";
8559 	      textline=0;
8560 	    }
8561 	    if (sres==6){
8562 	      display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8563 	      search=get_searchitem(replace);
8564 	      if (!search.empty()){
8565 		for (;;){
8566 		  if (!move_to_word(text,search,replace,isFirstDraw,totalTextY,scroll,textY,contextptr)){
8567 		    break;
8568 		  }
8569 		}
8570 		show_status(text,search,replace);
8571 	      }
8572 	    }
8573 	    if (sres==7){
8574 	      display(text,isFirstDraw,totalTextY,scroll,textY,contextptr);
8575 	      int l=get_line_number((lang==1)?"Negatif: en partant de la fin":"Negative: counted from the end",(lang==1)?"Numero de ligne:":"Line number:");
8576 	      if (l>0)
8577 		text->line=l-1;
8578 	      if (l<0)
8579 		text->line=v.size()+l;
8580 	    }
8581 	    if (sres==8){
8582 	      int c=select_interpreter();
8583 	      if (c>=0){
8584 		int p=text->python;
8585 		if (c==3)
8586 		  p |= 0x4;
8587 		else
8588 		  p=c;
8589 		giac::python_compat(p,contextptr);
8590 		text->python=p;
8591 		xcas_python_eval=c==3;
8592 		show_status(text,search,replace);
8593 		warn_python(text->python,false);
8594 		drawRectangle(0,205,LCD_WIDTH_PX,17,44444);
8595 		PrintMiniMini(0,205,"shift-1 test|2 loop|3 undo|4 misc|5 +- |      ",4,44444,giac::_BLACK);
8596 	      }
8597 	    }
8598 	  }
8599 	}
8600 	break;
8601       case KEY_CTRL_SETUP: // inactive
8602 	text->python=text->python?0:1;
8603 	show_status(text,search,replace);
8604 	python_compat(text->python,contextptr);
8605 	warn_python(text->python,false);
8606 	drawRectangle(0,205,LCD_WIDTH_PX,17,44444);
8607 	PrintMiniMini(0,205,"shift-1 test|2 loop|3 undo|4 misc|5 +- |      ",4,44444,giac::_BLACK);
8608 	continue;
8609       case KEY_CTRL_F2:
8610 	if (clipline<0)
8611 	  return KEY_CTRL_F2;
8612       case KEY_CTRL_EXIT:
8613 	if (clipline>=0){
8614 	  clipline=-1;
8615 	  show_status(text,search,replace);
8616 	  continue;
8617 	}
8618 	if (!search.empty()){
8619 	  search="";
8620 	  show_status(text,search,replace);
8621 	  continue;
8622 	}
8623 	if (check_leave(text)==2)
8624 	  continue;
8625 	return TEXTAREA_RETURN_EXIT;
8626       case KEY_CTRL_INS:
8627 	break;
8628       default:
8629 	if (clipline<0 && key>=32 && key<128 && editable){
8630 	  char buf[2]={char(key),0};
8631 	  insert(text,buf,false);
8632 	  show_status(text,search,replace);
8633 	}
8634 	if (key==KEY_CTRL_AC){
8635 	  if (clipline>=0){
8636 	    clipline=-1;
8637 	    show_status(text,search,replace);
8638 	  }
8639 	  else {
8640 	    if (search.size()){
8641 	      search="";
8642 	      show_status(text,search,replace);
8643 	    }
8644 	    else {
8645 	      copy_clipboard(v[textline].s+'\n',true);
8646 	      if (v.size()==1)
8647 		v[0].s="";
8648 	      else {
8649 		v.erase(v.begin()+textline);
8650 		if (textline>=v.size())
8651 		  --textline;
8652 	      }
8653 	      DefineStatusMessage((char*)"Line cut and copied to clipboard", 1, 0, 0);
8654 	      DisplayStatusArea();
8655 	    }
8656 	  }
8657 	}
8658       }
8659     }
8660   }
8661 
reload_edptr(const char * filename,textArea * edptr,GIAC_CONTEXT)8662   void reload_edptr(const char * filename,textArea *edptr,GIAC_CONTEXT){
8663     if (edptr){
8664       std::string s(merge_area(edptr->elements));
8665       copy_clipboard(s,true);
8666       s="\n";
8667       edptr->elements.clear();
8668       edptr->clipline=-1;
8669       edptr->filename=remove_path(giac::remove_extension(filename))+".py";
8670       load_script((char *)edptr->filename.c_str(),s);
8671       if (s.empty())
8672 	s="\n";
8673       // cout << "script " << edptr->filename << endl;
8674       edptr->editable=true;
8675       edptr->changed=false;
8676       edptr->python=python_compat(contextptr);
8677       edptr->elements.clear();
8678       edptr->y=7;
8679       add(edptr,s);
8680       edptr->line=0;
8681       edptr->pos=0;
8682     }
8683   }
8684 
8685   console_line * Line=0;//[_LINE_MAX];//={data_line};
8686   char menu_f1[8]={0},menu_f2[8]={0},menu_f3[8]={0},menu_f4[8]={0},menu_f5[8]={0},menu_f6[8];
8687   char session_filename[MAX_FILENAME_SIZE+1]="session";
8688   char * FMenu_entries_name[6]={menu_f1,menu_f2,menu_f3,menu_f4,menu_f5,menu_f6};
8689   location Cursor;
8690   char *Edit_Line=0;
8691   int Start_Line, Last_Line,editline_cursor;
8692   int Case;
8693   int console_changed=0; // 1 if something new in history
8694   int dconsole_mode=1; // 0 disables dConsole commands
8695 
8696 #define Current_Line (Start_Line + Cursor.y)
8697 #define Current_Col (Line[Cursor.y + Start_Line].start_col + Cursor.x)
8698 
console_disp_status(GIAC_CONTEXT)8699   void console_disp_status(GIAC_CONTEXT){
8700     int i=python_compat(contextptr);
8701     string msg;
8702     if (i&4)
8703       msg="MicroPython";
8704     else {
8705       if (i==0)
8706 	msg="Xcas";
8707       else {
8708 	if (i==1)
8709 	  msg="Py ^=**";
8710 	else
8711 	  msg="Py ^=xor";
8712       }
8713     }
8714     if (angle_radian(contextptr))
8715       msg += " RAD ";
8716     else
8717       msg += " DEG ";
8718     msg += session_filename;
8719     if (console_changed)
8720       msg += " *";
8721     statuslinemsg(msg.c_str());
8722     set_xcas_status();
8723     Bdisp_PutDisp_DD();
8724   }
8725 
leave_exam_mode(GIAC_CONTEXT)8726   void leave_exam_mode(GIAC_CONTEXT){
8727 #ifdef NSPIRE_NEWLIB
8728     // FIXME test USB connection instead
8729     unsigned NSPIRE_RTC_ADDR=0x90090000;
8730     unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR;
8731     int chk=0;
8732     if (exam_duration<=0 || (t1-exam_start<exam_duration)){
8733       chk=-1;
8734 #if 1 // checkin the  power management addresses range
8735       unsigned poweraddr=0x900b0028;
8736       unsigned u=*(unsigned *)poweraddr;
8737       //*logptr(contextptr) << "power " << u << '\n';
8738       if ( (u&0xff0000)==0x070000) // connected 0x11070114, disconnected 0x11110114
8739 	chk=0;
8740 #endif
8741 #if 0 /// check connection, works only if graph link connection before
8742       unsigned powermanagement_lockaddr=0x900b0018;
8743       // Bit 5: #B0000000 - USB OTG controller
8744       // Bit 6: #B4000000 - USB HOST controller
8745       *(unsigned *)powermanagement_lockaddr=0x8400a5d;
8746       unsigned HW_USBCTRL_PORTSC1=0xb0000184;
8747       unsigned u=*(unsigned *) HW_USBCTRL_PORTSC1;
8748       if ( (u&0xff000000)==0x11000000) // 0x11000805 vs 0x1d000004
8749 	chk=0;
8750       // B00001A4 might be used as well: HW_USBCTRL_OTGSC 1f202d20 vs 1f3c1120
8751 #endif
8752 #if 0 // check USB does not work
8753       nn_ch_t ch = NULL;
8754       nn_oh_t oh = NULL;
8755       nn_nh_t nh = NULL;
8756       oh = TI_NN_CreateOperationHandle();
8757       int ans=TI_NN_NodeEnumInit((nn_ch_t) oh);//(ch);
8758       *logptr(contextptr) << "enuminit" << ans << '\n';
8759       if (ans>=0){
8760 	ans=TI_NN_NodeEnumNext(oh, &nh);
8761 	*logptr(contextptr) << "enumnext" << ans << '\n';
8762 	if (ans>=0){
8763 	  ans=TI_NN_Connect(nh, 0x4060, &ch);
8764 	  *logptr(contextptr) << "connect" << ans << '\n';
8765 	  if (ans>=0){
8766 	    if(ch){
8767 	      TI_NN_Disconnect(ch);
8768 	      chk=0;
8769 	    }
8770 	  }
8771 	}
8772 	TI_NN_NodeEnumDone(oh);
8773 	TI_NN_DestroyOperationHandle(oh);
8774       }
8775 #endif
8776     }
8777 #else
8778     int chk=0;
8779 #endif
8780     if (chk>=0){
8781       set_exam_mode(0,contextptr);
8782     }
8783     if (exam_mode)
8784       confirm((lang==1)?"Pour arreter le mode examen":"To stop exam mode",(lang==1)?"branchez la calculatrice puis menu menu":"plug in the calculator then menu menu");
8785     else
8786       confirm((lang==1)?"Fin du mode examen":"End exam mode","enter: OK");
8787   }
8788 
menu_setup(GIAC_CONTEXT)8789   void menu_setup(GIAC_CONTEXT){
8790     Menu smallmenu;
8791     smallmenu.numitems=13;
8792     MenuItem smallmenuitems[smallmenu.numitems];
8793     smallmenu.items=smallmenuitems;
8794     smallmenu.height=12;
8795     smallmenu.scrollbar=1;
8796     smallmenu.scrollout=1;
8797     smallmenu.title = (char*)"Config";
8798 #ifdef NUMWORKS
8799     smallmenuitems[0].type = MENUITEM_CHECKBOX;
8800     smallmenuitems[0].text = (char*)"x,n,t -> t";
8801 #endif
8802     smallmenuitems[1].text = (char*)"Syntaxe (Xcas/Python)";
8803     smallmenuitems[2].type = MENUITEM_CHECKBOX;
8804     smallmenuitems[2].text = (char*)"Radians (in Xcas)";
8805     smallmenuitems[3].type = MENUITEM_CHECKBOX;
8806     smallmenuitems[3].text = (char*)"Sqrt (in Xcas)";
8807     smallmenuitems[4].text = (char*)"Francais";
8808     smallmenuitems[5].text = (char*)"English";
8809     smallmenuitems[6].text = (char*)"Spanish&English";
8810     smallmenuitems[7].text = (char*)"Greek&English";
8811     smallmenuitems[8].text = (char*)"Deutsch&English";
8812     smallmenuitems[9].text = (char *) ((lang==1)?"Raccourcis clavier (0)":"Shortcuts (0)");
8813     smallmenuitems[10].text = (char*) ((lang==1)?"Mode examen (e^x)":"Exam mode (e^x)");
8814     smallmenuitems[11].text = (char*) ((lang==1)?"A propos":"About");
8815     smallmenuitems[12].text = (char*) "Quit";
8816     if (exam_mode)
8817       smallmenuitems[12].text = (char*)((lang==1)?"Quitter le mode examen":"Quit exam mode");
8818 
8819     // smallmenuitems[2].text = (char*)(isRecording ? "Stop Recording" : "Record Script");
8820     while(1) {
8821 #ifdef NUMWORKS
8822       smallmenuitems[0].value = xthetat;
8823 #else
8824       string dig("Digits (in Xcas): ");
8825       dig += print_INT_(decimal_digits(contextptr));
8826       smallmenuitems[0].text = (char*)dig.c_str();
8827 #endif
8828       int p=python_compat(contextptr);
8829       if (p&4)
8830 	smallmenuitems[1].text = (char*)"Change syntax (MicroPython)";
8831       else {
8832 	if (p==0)
8833 	  smallmenuitems[1].text = (char*)"Change syntax (Xcas)";
8834 	if (p==1)
8835 	  smallmenuitems[1].text = (char*)"Change syntax (Xcas comp Python ^=**)";
8836 	if (p==2)
8837 	  smallmenuitems[1].text = (char*)"Change syntax (Xcas comp Python ^=xor)";
8838       }
8839       smallmenuitems[2].value = giac::angle_radian(contextptr);
8840       smallmenuitems[3].value = giac::withsqrt(contextptr);
8841       int sres = doMenu(&smallmenu);
8842       if (sres==MENU_RETURN_EXIT)
8843 	break;
8844       if (sres == MENU_RETURN_SELECTION  || sres==KEY_CTRL_EXE) {
8845 	if (smallmenu.selection == 1){
8846 #ifdef NUMWORKS
8847 	  xthetat=1-xthetat;
8848 #else
8849 	  double d=decimal_digits(contextptr);
8850 	  if (inputdouble("Nombre de digits?",d,contextptr) && d==int(d) && d>0){
8851 	    decimal_digits(d,contextptr);
8852 	  }
8853 #endif
8854 	  continue;
8855 	}
8856 	if (smallmenu.selection == 2){
8857 	  int c=select_interpreter();
8858 	  if (c>=0){
8859 	    int p=giac::python_compat(contextptr);
8860 	    if (c==3)
8861 	      p |= 0x4;
8862 	    else
8863 	      p=c;
8864 	    xcas_python_eval=c==3;
8865 	    giac::python_compat(p,contextptr);
8866 	    warn_python(p,false);
8867 	    if (edptr)
8868 	      edptr->python=p;
8869 	    Console_FMenu_Init(contextptr);
8870 	    console_disp_status(contextptr);
8871 	    break;
8872 	  }
8873 	}
8874 	if (smallmenu.selection == 3){
8875 	  giac::angle_radian(!giac::angle_radian(contextptr),contextptr);
8876 	  os_set_angle_unit(giac::angle_radian(contextptr)?0:1);
8877 	  statusline();
8878 	  continue;
8879 	}
8880 	if (smallmenu.selection == 4){
8881 	  giac::withsqrt(!giac::withsqrt(contextptr),contextptr);
8882 	  continue;
8883 	}
8884 	if (smallmenu.selection>=5 && smallmenu.selection<=9){
8885 	  lang=smallmenu.selection-4;
8886 	  giac::language(lang,contextptr);
8887 	  break;
8888 	}
8889 	if (smallmenu.selection == 11){
8890 	  if (!exam_mode && confirm((lang==1?"Verifiez que le calcul formel est autorise.":"Please check that the CAS is allowed."),(lang==1?"France: autorise au bac. Enter: ok, esc: annul":"enter: yes, esc: no"))!=KEY_CTRL_F1)
8891 	    break;
8892 	  // confirmation, duree (>=0 French indicative, else not indicative)
8893 	  double duration=exam_mode?absint(exam_duration):0;
8894 	  string msg=(lang==1)?"Compte a rebours en h.min ou 0 pour horloge":"Exam duration in h.min (0: end by pluging)";
8895 	  msg += print_duration(duration);
8896 	  if (inputdouble(msg.c_str(),duration,contextptr)){
8897 	    bool indicative=lang==1?duration>=0:duration<=0;
8898 	    if (exam_mode)
8899 	      indicative=exam_duration<=0;
8900 	    else {
8901 	      if (lang==1 && !indicative && confirm("Attention, mode non conforme au bac en France","enter: corriger, esc: tant pis")!=KEY_CTRL_F6)
8902 		indicative=true;
8903 	    }
8904 	    if (duration<0)
8905 	      duration=-duration;
8906 	    if (duration>10)
8907 	      duration=duration/60;
8908 	    else
8909 	      duration=std::floor(duration)+100.0/60*(duration-std::floor(duration));
8910 	    if (duration){
8911 	      msg=lang==1?"Duree compte a rebours ":"Exam duration ";
8912 	      double d=giacmax(duration*3600,absint(exam_duration));
8913 	      msg += print_duration(d);
8914 	    }
8915 	    else
8916 	      msg="Mode examen.";
8917 	    if (indicative)
8918 	      msg += lang==1?" Fin par branchement":" Exit by pluging";
8919 	    if (confirm(msg.c_str(),(lang==1?"!Blocage dans Xcas en mode exam! enter OK, esc annul":"!Trapped in Xcas in exam mode! enter OK, esc cancel."))==KEY_CTRL_F1){
8920 #ifdef NSPIRE_NEWLIB
8921 	      if (exam_mode)
8922 		exam_duration=duration?giacmax(absint(exam_duration),duration*3600+30):0;
8923 	      else {
8924 		unsigned NSPIRE_RTC_ADDR=0x90090000;
8925 		exam_start= * (volatile unsigned *) NSPIRE_RTC_ADDR;
8926 		exam_duration = duration?duration*3600+30:0;
8927 	      }
8928 	      if (indicative)
8929 		exam_duration=-absint(exam_duration);
8930 #else
8931 	      exam_start=0;
8932 	      exam_duration=1;
8933 #endif
8934 	      set_exam_mode(1,contextptr);
8935 	      do_restart(contextptr);
8936 	      clear_turtle_history(contextptr);
8937 	      Console_Init(contextptr);
8938 	      Console_Clear_EditLine();
8939 	      console_changed=0;
8940 	      strcpy(session_filename,"session.xw");
8941 	      save_session(contextptr);
8942 	      if (edptr){
8943 		edptr->elements.resize(1);
8944 		edptr->elements[0].s="";
8945 		edptr->undoelements=edptr->elements;
8946 		edptr->line=0;
8947 		edptr->pos=0;
8948 	      }
8949 	      save_script("session.py","");
8950 	    }
8951 	  }
8952 	  break;
8953 	}
8954 	if (smallmenu.selection == 13){
8955 	  if (exam_mode)
8956 	    leave_exam_mode(contextptr);
8957 	  break;
8958 	}
8959 	if (smallmenu.selection >= 10) {
8960 	  textArea text;
8961 	  text.editable=false;
8962 	  text.clipline=-1;
8963 	  text.title = smallmenuitems[smallmenu.selection-1].text;
8964 	  add(&text,smallmenu.selection==10?((lang==1)?shortcuts_fr_string:shortcuts_en_string):((lang==1)?apropos_fr_string:apropos_en_string));
8965 	  if (doTextArea(&text,contextptr)==KEY_SHUTDOWN)
8966 	    return ;
8967 	  continue;
8968 	}
8969       }
8970     }
8971   }
8972 
console_malloc(unsigned s)8973   void * console_malloc(unsigned s){
8974     return new char [s];
8975     // return malloc(s);
8976   }
8977 
console_free(void * ptr)8978   void console_free(void * ptr){
8979     delete [] (char *) ptr;
8980     // free(ptr);
8981   }
8982 
cleanup(std::string & s)8983   void cleanup(std::string & s){
8984     for (size_t i=0;i<s.size();++i){
8985       if (s[i]=='\n')
8986 	s[i]=' ';
8987     }
8988   }
8989 
8990   const int max_lines_saved=50;
8991 
run(const char * s,int do_logo_graph_eqw,GIAC_CONTEXT)8992   int run(const char * s,int do_logo_graph_eqw,GIAC_CONTEXT){
8993     if (strlen(s)>=2 && (s[0]=='#' ||
8994 			 (s[0]=='/' && (s[1]=='/' || s[1]=='*'))
8995 			 ))
8996       return 0;
8997     if (strcmp(s,"xcas")==0){
8998       xcas_python_eval=0;
8999       python_compat(python_compat(contextptr)&3,contextptr);
9000       if (edptr)
9001 	edptr->python=0;
9002       *logptr(contextptr) << "Xcas interpreter\n";
9003       Console_FMenu_Init(contextptr);
9004       return 0;
9005     }
9006     if (strcmp(s,"python")==0){
9007       xcas_python_eval=1;
9008       python_compat(4|python_compat(contextptr),contextptr);
9009       if (edptr)
9010 	edptr->python=1;
9011       *logptr(contextptr) << "Micropython interpreter\n";
9012       Console_FMenu_Init(contextptr);
9013       return 0;
9014     }
9015     gen g,ge;
9016 #ifdef MICROPY_LIB
9017     if (xcas_python_eval==1){
9018       freezeturtle=false;
9019       micropy_eval(s);
9020     }
9021     else
9022       do_run(s,g,ge,contextptr);
9023 #else
9024     do_run(s,g,ge,contextptr);
9025 #endif
9026     process_freeze();
9027 #ifdef MICROPY_LIB
9028     if (xcas_python_eval==1)
9029       return 0;
9030 #endif
9031     int t=giac::taille(g,GIAC_HISTORY_MAX_TAILLE);
9032     int te=giac::taille(ge,GIAC_HISTORY_MAX_TAILLE);
9033     bool do_tex=false;
9034     if (t<GIAC_HISTORY_MAX_TAILLE && te<GIAC_HISTORY_MAX_TAILLE){
9035       giac::vecteur &vin=history_in(contextptr);
9036       giac::vecteur &vout=history_out(contextptr);
9037       if (vin.size()>GIAC_HISTORY_SIZE)
9038 	vin.erase(vin.begin());
9039       vin.push_back(g);
9040       if (vout.size()>GIAC_HISTORY_SIZE)
9041 	vout.erase(vout.begin());
9042       vout.push_back(ge);
9043     }
9044     if (check_do_graph(ge,do_logo_graph_eqw,contextptr)==KEY_SHUTDOWN)
9045       return KEY_SHUTDOWN;
9046     string s_;
9047     if (ge.type==giac::_STRNG)
9048       s_='"'+*ge._STRNGptr+'"';
9049     else {
9050       if (te>256)
9051 	s_="Object too large";
9052       else {
9053 	if (ge.is_symb_of_sommet(giac::at_pnt) || (ge.type==giac::_VECT && !ge._VECTptr->empty() && ge._VECTptr->back().is_symb_of_sommet(giac::at_pnt)))
9054 	  s_="Graphic object";
9055 	else {
9056 	  //do_tex=ge.type==giac::_SYMB && has_op(ge,*giac::at_inv);
9057 	  // tex support has been disabled!
9058 	  s_=ge.print(contextptr);
9059 	  // translate to tex? set do_tex to true
9060 	}
9061       }
9062     }
9063 #ifdef NUMWORKS
9064     if (s_.size()>512)
9065       s_=s_.substr(0,509)+"...";
9066 #else
9067     if (s_.size()>8192)
9068       s_=s_.substr(0,8189)+"...";
9069 #endif
9070     char* edit_line = (char*)Console_GetEditLine();
9071     Console_Output((const char*)s_.c_str());
9072     return 0;
9073   }
9074 
run_session(int start,GIAC_CONTEXT)9075   int run_session(int start,GIAC_CONTEXT){
9076     std::vector<std::string> v;
9077     for (int i=start;i<Last_Line;++i){
9078       if (Line[i].type==LINE_TYPE_INPUT)
9079 	v.push_back((const char *)Line[i].str);
9080       console_free(Line[i].str);
9081       Line[i].str=0;
9082       Line[i].readonly = 0;
9083       Line[i].type = LINE_TYPE_INPUT;
9084       Line[i].start_col = 0;
9085       Line[i].disp_len = 0;
9086     }
9087     Line[Last_Line].str=0;
9088     Last_Line=start;
9089     Start_Line=Last_Line>LINE_DISP_MAX?Last_Line-LINE_DISP_MAX:0;
9090     Cursor.x=0;
9091     Cursor.y=start;
9092     Line[start].str=Edit_Line;
9093     Edit_Line[0]=0;
9094     if (v.empty()) return 0;
9095     //Console_Init(contextptr);
9096     for (int i=0;i<v.size();++i){
9097       Console_Output((const char *)v[i].c_str());
9098       //int j=Last_Line;
9099       Console_NewLine(LINE_TYPE_INPUT, 1);
9100       // Line[j].type=LINE_TYPE_INPUT;
9101       run(v[i].c_str(),6,contextptr); /* show logo and graph but not eqw */
9102       // j=Last_Line;
9103       Console_NewLine(LINE_TYPE_OUTPUT, 1);
9104       // Line[j].type=LINE_TYPE_OUTPUT;
9105       Console_Disp(1,contextptr);
9106       Bdisp_PutDisp_DD();
9107     }
9108     return 0;
9109   }
9110 
9111 
khicas_state(GIAC_CONTEXT)9112   string khicas_state(GIAC_CONTEXT){
9113     giac::gen g(giac::_VARS(-1,contextptr));
9114     int b=python_compat(contextptr);
9115     python_compat(0,contextptr);
9116 #if 1
9117 #ifdef NSPIRE_NEWLIB
9118     char *buf=nspire_filebuf;
9119     buf[0]=0;
9120     int bufsize=NSPIRE_FILEBUFFER;
9121 #else
9122     char buf[6144]="";
9123     int bufsize=sizeof(buf);
9124 #endif
9125     if (g.type==giac::_VECT){
9126       bool ok=true;
9127       for (int i=0;i<g._VECTptr->size();++i){
9128 	string s((*g._VECTptr)[i].print(contextptr));
9129 	if (strlen(buf)+s.size()+128<bufsize){
9130 	  strcat(buf,s.c_str());
9131 	  strcat(buf,":;");
9132 	}
9133 	else
9134 	  ok=false;
9135       }
9136       if (!ok){
9137 	confirm((lang==1)?"Contexte trop lourd, non sauvegarde":"Context too havy, not saved.",(lang==1)?"Re-executez scripts au chargement (esc enter)":"Re-run scripts at load time (esc enter)",true,64);
9138 	buf[0]=0;
9139       }
9140     }
9141     python_compat(b,contextptr);
9142     if (strlen(buf)+128<bufsize){
9143       strcat(buf,"python_compat(");
9144       strcat(buf,giac::print_INT_(b).c_str());
9145       strcat(buf,");angle_radian(");
9146       strcat(buf,angle_radian(contextptr)?"1":"0");
9147       strcat(buf,");with_sqrt(");
9148       strcat(buf,withsqrt(contextptr)?"1":"0");
9149       strcat(buf,");integer_format(");
9150       strcat(buf,integer_format(contextptr)==16?"16":"10");
9151       strcat(buf,");set_language(");
9152       char l[]="0";
9153       l[0]+=lang;
9154       strcat(buf,l);
9155       strcat(buf,");");
9156     }
9157     if (sheetptr){
9158       string s(current_sheet(vecteur(0),contextptr).print(contextptr));
9159       if (strlen(buf)+s.size()+20<bufsize){
9160 	strcat(buf,"current_sheet(");
9161 	strcat(buf,s.c_str());
9162 	strcat(buf,");");
9163       }
9164     }
9165     return buf;
9166 #else
9167     string s(g.print(contextptr));
9168     python_compat(b,contextptr);
9169     s += "; python_compat(";
9170     s +=  giac::print_INT_(b);
9171     s += ");angle_radian(";
9172     s += angle_radian(contextptr)?'1':'0';
9173     s += ");with_sqrt(";
9174     s += withsqrt(contextptr)?'1':'0';
9175     s += ");";
9176     return s;
9177 #endif
9178   }
Bfile_WriteFile_OS(char * & buf,const void * ptr,size_t len)9179   void Bfile_WriteFile_OS(char * & buf,const void * ptr,size_t len){
9180     memcpy(buf,ptr,len);
9181     buf += len;
9182   }
Bfile_WriteFile_OS4(char * & buf,size_t n)9183   void Bfile_WriteFile_OS4(char * & buf,size_t n){
9184     buf[0]= n>>24;
9185     buf[1]= (n>>16) & 0xff;
9186     buf[2]= (n & 0xffff)>>8;
9187     buf[3]= n & 0xff;
9188     buf += 4;
9189   }
Bfile_WriteFile_OS2(char * & buf,unsigned short n)9190   void Bfile_WriteFile_OS2(char * & buf,unsigned short n){
9191     buf[0]= n>>8;
9192     buf[1]= n & 0xff;
9193     buf += 2;
9194   }
save_console_state_smem(const char * filename,GIAC_CONTEXT)9195   void save_console_state_smem(const char * filename,GIAC_CONTEXT){
9196     console_changed=0;
9197     string state(khicas_state(contextptr));
9198     int statesize=state.size();
9199     string script;
9200     if (edptr)
9201       script=merge_area(edptr->elements);
9202     int scriptsize=script.size();
9203     // save format: line_size (2), start_col(2), line_type (1), readonly (1), line
9204     int size=2*sizeof(int)+statesize+scriptsize;
9205     int start_row=Last_Line-max_lines_saved;
9206     if (start_row<0) start_row=0;
9207     for (int i=start_row;i<=Last_Line;++i){
9208       size += 2*sizeof(short)+2*sizeof(char)+strlen((const char *)Line[i].str);
9209     }
9210     char savebuf[size+4];
9211 #ifdef NUMWORKS
9212     char * hFile=savebuf+1;
9213 #else
9214     char * hFile=savebuf;
9215 #endif
9216     // save variables and modes
9217     Bfile_WriteFile_OS4(hFile, statesize);
9218     Bfile_WriteFile_OS(hFile, state.c_str(), statesize);
9219     // save script
9220     Bfile_WriteFile_OS4(hFile, scriptsize);
9221     Bfile_WriteFile_OS(hFile, script.c_str(), scriptsize);
9222     // save console state
9223     // save console state
9224     for (int i=start_row;i<=Last_Line;++i){
9225       console_line & cur=Line[i];
9226       unsigned short l=strlen((const char *)cur.str);
9227       Bfile_WriteFile_OS2(hFile, l);
9228       unsigned short s=cur.start_col;
9229       Bfile_WriteFile_OS2(hFile, s);
9230       unsigned char c=cur.type;
9231       Bfile_WriteFile_OS(hFile, &c, sizeof(c));
9232       c=1;//cur.readonly;
9233       Bfile_WriteFile_OS(hFile, &c, sizeof(c));
9234       unsigned char buf[l+1];
9235       buf[l]=0;
9236       strcpy((char *)buf,(const char*)cur.str);
9237       unsigned char *ptr=buf,*strend=ptr+l;
9238       for (;ptr<strend;++ptr){
9239 	if (*ptr==0x9c)
9240 	  *ptr='\n';
9241       }
9242       Bfile_WriteFile_OS(hFile, buf, l);
9243     }
9244     char BUF[2]={0,0};
9245     Bfile_WriteFile_OS(hFile, BUF, sizeof(BUF));
9246 #ifdef NUMWORKS
9247     savebuf[0]=1;
9248 #endif
9249     int len=hFile-savebuf;
9250     write_file(filename,savebuf,len);
9251   }
9252 
Bfile_ReadFile_OS4(const char * & hf)9253   size_t Bfile_ReadFile_OS4(const char * & hf){
9254     size_t n=(((((hf[0]<<8)+hf[1])<<8)+hf[2])<<8)+hf[3];
9255     hf += 4;
9256     return n;
9257   }
9258 
Bfile_ReadFile_OS2(const char * & hf)9259   size_t Bfile_ReadFile_OS2(const char * & hf){
9260     size_t n=(hf[0]<<8)+hf[1];
9261     hf += 2;
9262     return n;
9263   }
9264 
Bfile_ReadFile_OS(const char * & hf,char * dest,size_t len)9265   void Bfile_ReadFile_OS(const char * &hf,char * dest,size_t len){
9266     memcpy(dest,hf,len);
9267     hf += len;
9268   }
9269 
load_console_state_smem(const char * filename,GIAC_CONTEXT)9270   bool load_console_state_smem(const char * filename,GIAC_CONTEXT){
9271     const char * hf=read_file(filename);
9272     if (!hf) return false;
9273     size_t L=Bfile_ReadFile_OS4(hf);
9274     char BUF[L+4];
9275     BUF[1]=BUF[0]='/'; // avoid trying python compat.
9276     BUF[2]='\n';
9277     Bfile_ReadFile_OS(hf,BUF+3,L);
9278     BUF[L+3]=0;
9279     giac::gen g,ge;
9280     dconsole_mode=0; python_compat(contextptr)=0; xcas_mode(contextptr)=0;
9281     bool bi=try_parse_i(contextptr);
9282     try_parse_i(false,contextptr);
9283     do_run((char*)BUF,g,ge,contextptr);
9284     try_parse_i(bi,contextptr);
9285     dconsole_mode=1;
9286     // read script
9287     L=Bfile_ReadFile_OS4(hf);
9288     if (L>0){
9289       char bufscript[L+1];
9290       Bfile_ReadFile_OS(hf,bufscript,L);
9291       bufscript[L]=0;
9292       if (edptr==0)
9293 	edptr=new textArea;
9294       if (edptr){
9295 	edptr->elements.clear();
9296 	edptr->clipline=-1;
9297 	edptr->filename=remove_path(giac::remove_extension(filename))+".py";
9298 	//cout << "script " << edptr->filename << endl;
9299 	edptr->editable=true;
9300 	edptr->changed=false;
9301 	edptr->python=python_compat(contextptr);
9302 	edptr->elements.clear();
9303 	edptr->y=0;
9304 	add(edptr,bufscript);
9305 	edptr->line=0;
9306 	//edptr->line=edptr->elements.size()-1;
9307 	edptr->pos=0;
9308       }
9309     }
9310     // read console state
9311     // insure parse messages are cleared
9312     Console_Init(contextptr);
9313     Console_Clear_EditLine();
9314     for (int pos=0;;++pos){
9315       unsigned short int l,curs;
9316       unsigned char type,readonly;
9317       if ( (l=Bfile_ReadFile_OS2(hf))==0) break;
9318       curs=Bfile_ReadFile_OS2(hf);
9319       type = *hf; ++hf;
9320       readonly=*hf; ++hf;
9321       char buf[l+1];
9322       Bfile_ReadFile_OS(hf,buf,l);
9323       buf[l]=0;
9324       // ok line ready in buf
9325       while (Line[Current_Line].readonly)
9326 	Console_MoveCursor(CURSOR_DOWN);
9327       Console_Input(buf);
9328       Console_NewLine(LINE_TYPE_INPUT, 1);
9329 #if 1
9330       if (Current_Line>0){
9331 	console_line & cur=Line[Current_Line-1];
9332 	cur.type=type;
9333 	cur.readonly=readonly;
9334 	cur.start_col+=curs;
9335       }
9336 #endif
9337     }
9338     console_changed=0;
9339     if (python_compat(contextptr)&4)
9340       xcas_python_eval=1;
9341     Console_FMenu_Init(contextptr); // insure the menus are sync-ed
9342     return true;
9343   }
9344 
9345   /*
9346 
9347     The following functions will be used to specify the location before deleting a string of n characters altogether. Among them, a wide character (2 bytes) will be counted as a character.
9348 
9349     For example, we have the following string str:
9350 
9351     Location  |  0  |  1  |  2  |  3  |  4  |  5  | 6 |
9352     Character | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 0 |
9353 
9354     After the call Console_DelStr (str, 3, 2), position 1 and 2 characters will be deleted, then the characters will be in advance.
9355 
9356     Results are as follows:
9357 
9358     Location  |  0  |  1  |  2  |  3  | 4 |  5  | 6 |
9359     Character | 'a' | 'd' | 'e' | 'f' | 0 | 'f' | 0 |
9360 
9361     (Note: the extra positions will not be filled with '\ 0', but '\ 0' will be a copy of the original end of the string.)
9362 
9363   */
9364 
Console_DelStr(char * str,int end_pos,int n)9365   int Console_DelStr(char *str, int end_pos, int n)
9366   {
9367     int str_len, actual_end_pos, start_pos, actual_start_pos, del_len, i;
9368 
9369     str_len = strlen((const char *)str);
9370     if ((start_pos = end_pos - n) < 0) return CONSOLE_ARG_ERR;
9371 
9372     if ((actual_end_pos = Console_GetActualPos(str, end_pos)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
9373     if ((actual_start_pos = Console_GetActualPos(str, start_pos)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
9374 
9375     del_len = actual_end_pos - actual_start_pos;
9376 
9377     for (i = actual_start_pos; i < str_len; i++)
9378       {
9379 	str[i] = str[i + del_len];
9380       }
9381 
9382     return CONSOLE_SUCCEEDED;
9383   }
9384 
9385   /*
9386 
9387     The following functions are used to specify the location of the insertion in the specified string.
9388     (Note: This refers to the position of the printing position when, rather than the actual position.)
9389   */
9390 
Console_InsStr(char * dest,const char * src,int disp_pos)9391   int Console_InsStr(char *dest, const char *src, int disp_pos)
9392   {
9393     int i, ins_len, str_len, actual_pos;
9394 
9395     ins_len = strlen((const char *)src);
9396     str_len = strlen((const char *)dest);
9397 
9398     actual_pos = Console_GetActualPos(dest, disp_pos);
9399 
9400     if (ins_len + str_len >= EDIT_LINE_MAX) return CONSOLE_MEM_ERR;
9401     if (actual_pos > str_len) return CONSOLE_ARG_ERR;
9402 
9403     for (i = str_len; i >= actual_pos; i--)
9404       {
9405 	dest[i + ins_len] = dest[i];
9406       }
9407 
9408     for (i = 0; i < ins_len; i++)
9409       {
9410 	char c=src[i];
9411 	if (c=='\n') c=0x9c;
9412 	dest[actual_pos + i] = (c==0x0a?' ':c);
9413       }
9414 
9415     return CONSOLE_SUCCEEDED;
9416   }
9417 
9418   /*
9419 
9420     The following function is used to determine the true position of the string corresponding to the printing position.
9421     For example, in the following this string str contains wide characters, the location of the print is as follows:
9422 
9423     Location  | 00  |  01 |   02  |  03  | 04   | 05  | 06  |
9424     Character | one | two | three | four | five | six | \ 0 |
9425 
9426     The actual storage location is as follows:
9427 
9428     Location | 	00  | 01   |  02  |  03  |  04  |  05  |  06  |  07  |  08  |  09  |  10  |  11  |
9429     Value 	 | 0xD2 | 0xBB | 0xB6 | 0xFE | 0xC8 | 0xFD | 0xCB | 0xC4 | 0xCE | 0xE5 | 0xC1 | 0xF9 |
9430 
9431     You can find the first four characters 'five' is actually stored in the eighth position.
9432     So, when you call Console_GetActualPos (str, 4), it will return 8.
9433   */
9434 
Console_GetActualPos(const char * str,int disp_pos)9435   int Console_GetActualPos(const char *str, int disp_pos)
9436   {
9437     int actual_pos, count;
9438 
9439     for (actual_pos = count = 0; count < disp_pos; count++)
9440       {
9441 	if (str[actual_pos] == '\0') return CONSOLE_ARG_ERR;
9442 
9443 	if (is_wchar(str[actual_pos]))
9444 	  {
9445 	    actual_pos += 2;
9446 	  }
9447 	else
9448 	  {
9449 	    actual_pos++;
9450 	  }
9451       }
9452 
9453     return actual_pos;
9454   }
9455 
9456   /*
9457     The following functions are used to obtain a string of print length, ie, a wide character (2 bytes) recorded as a character.
9458   */
9459 
Console_GetDispLen(const char * str)9460   int Console_GetDispLen(const char *str)
9461   {
9462     int i, len;
9463 
9464     for (i = len = 0; str[i]!='\0'; len++)
9465       {
9466 	if (is_wchar(str[i]))
9467 	  {
9468 	    i += 2;
9469 	  }
9470 	else
9471 	  {
9472 	    i++;
9473 	  }
9474       }
9475 
9476     return len;
9477   }
9478 
9479   /*
9480     The following functions are used to move the cursor.
9481   */
9482 
Console_MoveCursor(int direction)9483   int Console_MoveCursor(int direction)
9484   {
9485     switch (direction)
9486       {
9487       case CURSOR_UP:
9488 	if (Current_Line==Last_Line)
9489 	  editline_cursor=Cursor.x;
9490 	//If you need to operate.
9491 	if ((Cursor.y > 0) || (Start_Line > 0)){
9492 	  //If the current line is not read-only, then Edit_Line copy to the current line.
9493 	  if (!Line[Current_Line].readonly){
9494 	    if ((Line[Current_Line].str = (char *)console_malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
9495 	    strcpy((char *)Line[Current_Line].str, (const char *)Edit_Line);
9496 	    Line[Current_Line].disp_len = Console_GetDispLen(Line[Current_Line].str);
9497 	    Line[Current_Line].type = LINE_TYPE_INPUT;
9498 	  }
9499 	  //If the cursor does not move to the top of, directly move the cursor upward.
9500 	  if (Cursor.y > 0)
9501 	    Cursor.y--;
9502 	  //Otherwise, the number of rows, if the screen's first line is not the first line, then began to show minus one.
9503 	  else {
9504 	    if (Start_Line > 0)
9505 	      Start_Line--;
9506 	  }
9507 	  //End if the horizontal position after moving the cursor over the line, then move the cursor to the end of the line.
9508 	  if (Cursor.x > Line[Current_Line].disp_len){
9509 	    Cursor.x = Line[Current_Line].disp_len;
9510 	  }
9511 	  else {
9512 	    if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX){
9513 	      if (Cursor.x == COL_DISP_MAX)
9514 		Cursor.x = COL_DISP_MAX - 1;
9515 	    }
9516 	  }
9517 	  //If you move the cursor to the line after the first, and the front of the line there is a character does not appear, then move the cursor to position 1.
9518 	  if (Cursor.x == 0 && Line[Current_Line].start_col > 0)
9519 	    Cursor.x = 1;
9520 	  //If the current cursor line is not read-only, then it is a string copy to Edit_Line for editing.
9521 	  if (!Line[Current_Line].readonly){
9522 	    strcpy((char *)Edit_Line, (const char *)Line[Current_Line].str);
9523 	    console_free(Line[Current_Line].str);
9524 	    Line[Current_Line].str = Edit_Line;
9525 	  }
9526 	}
9527 	break;
9528       case CURSOR_ALPHA_UP:{
9529 	int pos1=Start_Line+Cursor.y;
9530 	Console_MoveCursor(CURSOR_UP);
9531 	int pos2=Start_Line+Cursor.y;
9532 	if (pos1<Last_Line && pos2<Last_Line && pos1!=pos2){
9533 	  console_line curline=Line[pos1];
9534 	  Line[pos1]=Line[pos2];
9535 	  Line[pos2]=curline;
9536 	}
9537 	break;
9538       }
9539       case CURSOR_ALPHA_DOWN: {
9540 	int pos1=Start_Line+Cursor.y;
9541 	Console_MoveCursor(CURSOR_DOWN);
9542 	int pos2=Start_Line+Cursor.y;
9543 	if (pos1<Last_Line && pos2<Last_Line && pos1!=pos2){
9544 	  console_line curline=Line[pos1];
9545 	  Line[pos1]=Line[pos2];
9546 	  Line[pos2]=curline;
9547 	}
9548 	break;
9549       }
9550       case CURSOR_DOWN:
9551 	if (Current_Line==Last_Line)
9552 	  editline_cursor=Cursor.x;
9553 	//If you need to operate.
9554 	if ((Cursor.y < LINE_DISP_MAX - 1) && (Current_Line < Last_Line) || (Start_Line + LINE_DISP_MAX - 1 < Last_Line))
9555 	  {
9556 	    //If the current line is not read-only, then Edit_Line copy to the current line.
9557 	    if (!Line[Current_Line].readonly)
9558 	      {
9559 		if ((Line[Current_Line].str = (char *)console_malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
9560 		strcpy((char *)Line[Current_Line].str, (const char *)Edit_Line);
9561 		Line[Current_Line].disp_len = Console_GetDispLen(Line[Current_Line].str);
9562 		Line[Current_Line].type = LINE_TYPE_INPUT;
9563 	      }
9564 
9565 	    //If the cursor does not move to the bottom, the cursor moves down directly.
9566 	    if (Cursor.y < LINE_DISP_MAX - 1 && Current_Line < Last_Line)
9567 	      {
9568 		Cursor.y++;
9569 	      }
9570 	    //The number of rows Otherwise, if the last line is not the last line on the screen, it will begin to show a plus.
9571 	    else if (Start_Line + LINE_DISP_MAX - 1 < Last_Line)
9572 	      {
9573 		Start_Line++;
9574 	      }
9575 
9576 	    //If you move the cursor after the end of the horizontal position over the line, then move the cursor to the end of the line.
9577 	    if (Cursor.x > Line[Current_Line].disp_len)
9578 	      {
9579 		Cursor.x = Line[Current_Line].disp_len;
9580 	      }
9581 	    else if (Line[Current_Line].disp_len - Line[Current_Line].start_col >= COL_DISP_MAX)
9582 	      {
9583 		if (Cursor.x == COL_DISP_MAX) Cursor.x = COL_DISP_MAX - 1;
9584 	      }
9585 
9586 	    //If you move the cursor to the line after the first, and the front of the line there is a character does not appear, then move the cursor to position 1.
9587 	    if (Cursor.x == 0 && Line[Current_Line].start_col > 0) Cursor.x = 1;
9588 
9589 	    //If the current cursor line is not read-only, then it is a string copy to Edit_Line for editing.
9590 	    if (!Line[Current_Line].readonly)
9591 	      {
9592 		strcpy((char *)Edit_Line, (const char *)Line[Current_Line].str);
9593 		console_free(Line[Current_Line].str);
9594 		Line[Current_Line].str = Edit_Line;
9595 	      }
9596 	  }
9597 	break;
9598       case CURSOR_LEFT:
9599 	if (Line[Current_Line].readonly){
9600 	  if (Line[Current_Line].start_col > 0){
9601 	    Line[Current_Line].start_col--;
9602 	  }
9603 	  break;
9604 	}
9605 	else {
9606 	  if (Line[Current_Line].start_col > 0){
9607 	    if (Cursor.x > 1)
9608 	      Cursor.x--;
9609 	    else
9610 	      Line[Current_Line].start_col--;
9611 	    break;
9612 	  }
9613 	  if (Cursor.x > 0){
9614 	    Cursor.x--;
9615 	    break;
9616 	  }
9617 	}
9618       case CURSOR_SHIFT_RIGHT:
9619 	if (!Line[Current_Line].readonly)
9620 	  Cursor.x=giacmin(Line[Current_Line].disp_len,COL_DISP_MAX);
9621 	if (Line[Current_Line].disp_len > COL_DISP_MAX)
9622 	  Line[Current_Line].start_col = Line[Current_Line].disp_len - COL_DISP_MAX;
9623 	break;
9624       case CURSOR_RIGHT:
9625 	if (Line[Current_Line].readonly){
9626 	  if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX){
9627 	    Line[Current_Line].start_col++;
9628 	  }
9629 	  break;
9630 	}
9631 	else {
9632 	  if (Line[Current_Line].disp_len - Line[Current_Line].start_col > COL_DISP_MAX){
9633 	    if (Cursor.x < COL_DISP_MAX - 1)
9634 	      Cursor.x++;
9635 	    else
9636 	      Line[Current_Line].start_col++;
9637 	    break;
9638 	  }
9639 	  if (Cursor.x < Line[Current_Line].disp_len - Line[Current_Line].start_col){
9640 	    Cursor.x++;
9641 	    break;
9642 	  }
9643 	}
9644       case CURSOR_SHIFT_LEFT:
9645 	if (!Line[Current_Line].readonly)
9646 	  Cursor.x=0;
9647 	Line[Current_Line].start_col=0;
9648 	break;
9649       default:
9650 	return CONSOLE_ARG_ERR;
9651 	break;
9652       }
9653     return CONSOLE_SUCCEEDED;
9654   }
9655 
9656   /*
9657     The following function is used for input.
9658     String input to the cursor, the cursor will automatically move.
9659   */
9660 
Console_Input(const char * str)9661   int Console_Input(const char *str)
9662   {
9663     console_changed=1;
9664     int old_len,i,return_val;
9665 
9666     if (!Line[Current_Line].readonly)
9667       {
9668 	old_len = Line[Current_Line].disp_len;
9669 	return_val = Console_InsStr(Edit_Line, str, Current_Col);
9670 	if (return_val != CONSOLE_SUCCEEDED) return return_val;
9671 	if ((Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
9672 	for (i = 0; i < Line[Current_Line].disp_len - old_len; i++)
9673 	  {
9674 	    Console_MoveCursor(CURSOR_RIGHT);
9675 	  }
9676 	return CONSOLE_SUCCEEDED;
9677       }
9678     else
9679       {
9680 	return CONSOLE_ARG_ERR;
9681       }
9682   }
9683 
9684   /*
9685     The following functions are used to output the string to the current line.
9686   */
9687 
Console_Output(const char * str)9688   int Console_Output(const char *str)  {
9689     if (!Line) return 0;
9690     console_changed=1;
9691     int return_val, old_len, i;
9692 
9693     if (!Line[Current_Line].readonly)
9694       {
9695 	old_len = Line[Current_Line].disp_len;
9696 
9697 	return_val = Console_InsStr(Edit_Line, str, Current_Col);
9698 	if (return_val != CONSOLE_SUCCEEDED) return return_val;
9699 	if ((Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
9700 	Line[Current_Line].type = LINE_TYPE_OUTPUT;
9701 
9702 	for (i = 0; i < Line[Current_Line].disp_len - old_len; i++)
9703 	  {
9704 	    Console_MoveCursor(CURSOR_RIGHT);
9705 	  }
9706 	return CONSOLE_SUCCEEDED;
9707       }
9708     else
9709       {
9710 	return CONSOLE_ARG_ERR;
9711       }
9712   }
9713 
dConsolePut(const char * S)9714   void dConsolePut(const char * S){
9715     if (!dconsole_mode)
9716       return;
9717     int l=strlen(S);
9718     char s[l+1];
9719     strcpy(s,S);
9720     for (int i=0;i<l;++i){
9721       if (s[i]=='\n' ||
9722 	  s[i]==10)
9723 	s[i]=' ';
9724     }
9725     Console_Output((const char *)s);
9726     if (l && S[l-1]=='\n'){
9727       Console_NewLine(LINE_TYPE_OUTPUT, 1);
9728       if (!freeze)
9729 	Console_Disp(1,0);
9730     }
9731   }
9732 
dPuts(const char * s)9733   void dPuts(const char * s){
9734     dConsolePut(s);
9735   }
9736 
9737 #define PUTCHAR_LEN 35
9738   static char putchar_buf[PUTCHAR_LEN+2];
9739   static int putchar_pos=0;
dConsolePutChar(const char ch)9740   void dConsolePutChar(const char ch){
9741     if (!dconsole_mode)
9742       return;
9743     if (putchar_pos==PUTCHAR_LEN)
9744       dConsolePutChar('\n');
9745     if (ch=='\n'){
9746       putchar_buf[putchar_pos]='\n';
9747       putchar_buf[putchar_pos+1]=0;
9748       putchar_pos=0;
9749       dConsolePut(putchar_buf);
9750     }
9751     else {
9752       putchar_buf[putchar_pos]=ch;
9753       ++putchar_pos;
9754     }
9755   }
9756 
9757   /*
9758     Clear the current output line
9759   */
9760 
Console_Clear_EditLine()9761   void Console_Clear_EditLine()
9762   {
9763     if(!Line[Current_Line].readonly) {
9764       Edit_Line[0] = '\0';
9765       Line[Current_Line].start_col = 0;
9766       Line[Current_Line].disp_len = 0;
9767       Cursor.x = 0;
9768     }
9769   }
9770 
9771   /*
9772 
9773     The following functions are used to create a new line.
9774     Pre_line_type type parameter is used to specify the line, pre_line_readonly parameter is used to specify the line is read-only.
9775     New_line_type parameter is used to specify the type of the next line, new_line_readonly parameter is used to specify the next line is read-only.
9776   */
9777 
Console_NewLine(int pre_line_type,int pre_line_readonly)9778   int Console_NewLine(int pre_line_type, int pre_line_readonly)
9779   {
9780     if (!Line) return 0;
9781     console_changed=1;
9782     int i;
9783 
9784     if (strlen((const char *)Edit_Line)||Line[Current_Line].type==LINE_TYPE_OUTPUT)
9785       {
9786 	//Èç¹ûÒѾ­ÊÇËùÄÜ´æ´¢µÄ×îºóÒ»ÐУ¬Ôòɾ³ýµÚÒ»ÐС£
9787 	//If this is the last line we can store, delete the first line.
9788 	if (Last_Line == _LINE_MAX - 1)
9789 	  {
9790 	    for (i = 0; i < Last_Line; i++)
9791 	      {
9792 		Line[i].disp_len = Line[i + 1].disp_len;
9793 		Line[i].readonly = Line[i + 1].readonly;
9794 		Line[i].start_col = Line[i + 1].start_col;
9795 		Line[i].str = Line[i + 1].str;
9796 		Line[i].type = Line[i + 1].type;
9797 	      }
9798 	    Last_Line--;
9799 
9800 	    if (Start_Line > 0) Start_Line--;
9801 	  }
9802 
9803 	if (Line[Last_Line].type == LINE_TYPE_OUTPUT && strlen((const char *)Edit_Line) == 0) Console_Output((const char *)"Done");
9804 
9805 	//Edit_Line copy the contents to the last line.
9806 
9807 	if ((Line[Last_Line].str = (char *)console_malloc(strlen((const char *)Edit_Line) + 1)) == NULL) return CONSOLE_MEM_ERR;
9808 	strcpy((char *)Line[Last_Line].str, (const char *)Edit_Line);
9809 
9810 	if ((Line[Last_Line].disp_len = Console_GetDispLen(Line[Last_Line].str)) == CONSOLE_ARG_ERR) return CONSOLE_ARG_ERR;
9811 	Line[Last_Line].type = pre_line_type;
9812 	Line[Last_Line].readonly = pre_line_readonly;
9813 	Line[Last_Line].start_col = 0;
9814 
9815 	Edit_Line[0] = '\0';
9816 
9817 	Last_Line++;
9818 
9819 	Cursor.x = 0;
9820 
9821 	if ((Last_Line - Start_Line) == LINE_DISP_MAX)
9822 	  {
9823 	    Start_Line++;
9824 	  }
9825 	else
9826 	  {
9827 	    Cursor.y++;
9828 	  }
9829 
9830 	Line[Last_Line].str = Edit_Line;
9831 	Line[Last_Line].readonly = 0;
9832 	Line[Last_Line].type = LINE_TYPE_INPUT;
9833 	Line[Last_Line].start_col = 0;
9834 	Line[Last_Line].disp_len = 0;
9835 
9836 	return CONSOLE_NEW_LINE_SET;
9837       }
9838     else
9839       {
9840 	return CONSOLE_NO_EVENT;
9841       }
9842   }
9843 
Console_Insert_Line()9844   void Console_Insert_Line(){
9845     if (Last_Line>=_LINE_MAX-1)
9846       return;
9847     for (int i=Last_Line;i>=Current_Line;--i){
9848       Line[i+1]=Line[i];
9849     }
9850     ++Last_Line;
9851     int i=Current_Line;
9852     console_line & l=Line[i];
9853     l.str=(char *)console_malloc(2);
9854     strcpy((char *)l.str,"0");
9855     l.type=Line[i+1].type==LINE_TYPE_INPUT?LINE_TYPE_OUTPUT:LINE_TYPE_INPUT;
9856     l.start_col=0;
9857     l.readonly=1;
9858     l.disp_len=Console_GetDispLen(l.str);
9859   }
9860 
9861   /*
9862     The following function is used to delete a character before the cursor.
9863   */
9864 
Console_Backspace(GIAC_CONTEXT)9865   int Console_Backspace(GIAC_CONTEXT){
9866     console_changed=1;
9867     if (Last_Line>0 && Current_Line<Last_Line){
9868       int i=Current_Line;
9869       if (Edit_Line==Line[i].str)
9870 	Edit_Line=Line[i+1].str;
9871       if (Line[i].str){
9872 	copy_clipboard((const char *)Line[i].str,true);
9873 	console_free(Line[i].str);
9874       }
9875       for (;i<Last_Line;++i){
9876 	Line[i]=Line[i+1];
9877       }
9878       Line[i].readonly = 0;
9879       Line[i].type = LINE_TYPE_INPUT;
9880       Line[i].start_col = 0;
9881       Line[i].disp_len = 0;
9882       Line[i].str=0;
9883       --Last_Line;
9884       if (Start_Line>0)
9885 	--Start_Line;
9886       else {
9887 	if (Cursor.y>0)
9888 	  --Cursor.y;
9889       }
9890 #if 1
9891       if (Last_Line==0 && Current_Line==0){ // workaround
9892 	char buf[strlen((const char*)Edit_Line)+1];
9893 	strcpy(buf,(const char*)Edit_Line);
9894 	Console_Init(contextptr);
9895 	Console_Clear_EditLine();
9896 	if (buf[0])
9897 	  Console_Input((const char *)buf);
9898 	//std::string status(giac::print_INT_(Last_Line)+" "+(giac::print_INT_(Current_Line)+" ")+giac::print_INT_(Line[Current_Line].str)+" "+(const char*)Line[Current_Line].str);
9899 	//DefineStatusMessage(status.c_str(),1,0,0);
9900 	//DisplayStatusArea();
9901       }
9902 #endif
9903       Console_Disp(1,0);
9904       return CONSOLE_SUCCEEDED;
9905     }
9906     int return_val;
9907     return_val = Console_DelStr(Edit_Line, Current_Col, 1);
9908     if (return_val != CONSOLE_SUCCEEDED) return return_val;
9909     Line[Current_Line].disp_len = Console_GetDispLen(Edit_Line);
9910     return Console_MoveCursor(CURSOR_LEFT);
9911   }
9912 
9913   /*
9914     The following functions are used to deal with the key.
9915   */
9916 
chk_clearscreen(GIAC_CONTEXT)9917   void chk_clearscreen(GIAC_CONTEXT){
9918     drawRectangle(0, 24, LCD_WIDTH_PX, LCD_HEIGHT_PX-24, COLOR_WHITE);
9919     if (confirm((lang==1)?"Effacer l'historique?":"Clear history?",
9920 #ifdef NSPIRE_NEWLIB
9921 		(lang==1)?"enter: oui, esc: conserver":"enter: yes, esc: keep",
9922 #else
9923 		(lang==1)?"OK: oui, Back: conserver":"OK: yes, Back: keep",
9924 #endif
9925 		false)==KEY_CTRL_F1){
9926       Console_Init(contextptr);
9927       Console_Clear_EditLine();
9928     }
9929     Console_Disp(1,0);
9930   }
9931 
9932 
9933   /*
9934     int handle_f5(){
9935     int keyflag = GetSetupSetting( (unsigned int)0x14);
9936     if (keyflag == 0x04 || keyflag == 0x08 || keyflag == 0x84 || keyflag == 0x88) {
9937     // ^only applies if some sort of alpha (not locked) is already on
9938     if (keyflag == 0x08 || keyflag == 0x88) { //if lowercase
9939     SetSetupSetting( (unsigned int)0x14, keyflag-0x04);
9940     DisplayStatusArea();
9941     return 1; //do not process the key, because otherwise we will leave alpha status
9942     } else {
9943     SetSetupSetting( (unsigned int)0x14, keyflag+0x04);
9944     DisplayStatusArea();
9945     return 1; //do not process the key, because otherwise we will leave alpha status
9946     }
9947     }
9948     if (keyflag==0) {
9949     SetSetupSetting( (unsigned int)0x14, 0x88);
9950     DisplayStatusArea();
9951     }
9952     return 0;
9953     }
9954   */
9955 
Console_Eval(const char * buf,GIAC_CONTEXT)9956   int Console_Eval(const char * buf,GIAC_CONTEXT){
9957     int start=Current_Line;
9958     console_free(Line[start].str);
9959     Line[start].str=(char *)console_malloc(strlen(buf)+1);
9960     strcpy((char *)Line[start].str,buf);
9961     run_session(start,contextptr);
9962     int move_line = Last_Line - start;
9963     for (int i = 0; i < move_line; i++)
9964       Console_MoveCursor(CURSOR_UP);
9965     return CONSOLE_SUCCEEDED;
9966   }
9967 
9968 
save(const char * fname,GIAC_CONTEXT)9969   void save(const char * fname,GIAC_CONTEXT){
9970     clear_abort();
9971 #if 0
9972     return;
9973 #else
9974     string filename(remove_path(remove_extension(fname)));
9975     filename+=".xw";
9976 #ifdef NSPIRE_NEWLIB
9977     filename+=".tns";
9978 #endif
9979     save_console_state_smem(filename.c_str(),contextptr); // call before save_khicas_symbols_smem(), because this calls create_data_folder if necessary!
9980     // save_khicas_symbols_smem(("\\\\fls0\\"+filename+".xw").c_str());
9981     if (edptr)
9982       check_leave(edptr);
9983 #endif
9984   }
9985 
restore_session(const char * fname,GIAC_CONTEXT)9986   int restore_session(const char * fname,GIAC_CONTEXT){
9987 #if 0
9988     return 0;
9989 #else
9990     // cout << "0" << fname << endl; Console_Disp(1); GetKey(&key);
9991     string filename(remove_path(remove_extension(fname)));
9992     filename+=string(".xw");
9993 #ifdef NSPIRE_NEWLIB
9994     filename+=string(".tns");
9995 #endif
9996     if (!load_console_state_smem(filename.c_str(),contextptr)){
9997       int x=0,y=0;
9998       PrintMini(x,y,"KhiCAS 1.6 (c) 2020 B. Parisse",TEXT_MODE_NORMAL, COLOR_BLACK, COLOR_WHITE);
9999       y +=18;
10000       PrintMini(x,y,"et al, License GPL 2",TEXT_MODE_NORMAL,COLOR_BLACK, COLOR_WHITE);
10001       y += 18;
10002 #ifdef NSPIRE_NEWLIB
10003       PrintMini(x,y,((lang==1)?"Taper menu plusieurs fois":"Type menu several times"),TEXT_MODE_NORMAL,COLOR_BLACK, COLOR_WHITE);
10004 #else
10005       PrintMini(x,y,((lang==1)?"Taper HOME plusieurs fois":"Type HOME several times"),TEXT_MODE_NORMAL,COLOR_BLACK, COLOR_WHITE);
10006 #endif
10007       y += 18;
10008       PrintMini(x,y,((lang==1)?"pour quitter KhiCAS.":"to leave KhiCAS."),TEXT_MODE_NORMAL,COLOR_BLACK, COLOR_WHITE);
10009       y += 18;
10010       PrintMini(x,y,(lang==1)?"Si le calcul formel est interdit":"If CAS is forbidden!",TEXT_MODE_NORMAL, COLOR_RED, COLOR_WHITE);
10011       y += 18;
10012 #ifdef NSPIRE_NEWLIB
10013       PrintMini(x,y,(lang==1)?"quittez Khicas (menu menu menu)":"Leave Khicas (menu menu menu)",TEXT_MODE_NORMAL, COLOR_RED, COLOR_WHITE);
10014       if (confirm("Interpreter? enter: Xcas, esc: MicroPython",(lang==1?"Peut se modifier depuis menu configuration":"May be changed later from menu configuration"),false,130)==KEY_CTRL_F6){
10015 	python_compat(4,contextptr);
10016 	xcas_python_eval=1;
10017 	*logptr(contextptr) << "Micropython interpreter\n";
10018 	Console_FMenu_Init(contextptr);
10019       }
10020       else {
10021 	python_compat(1,contextptr);
10022 	*logptr(contextptr) << "Xcas interpreter, Python compatible mode\n";
10023       }
10024 #else
10025       PrintMini(x,y,(lang==1)?"quittez Khicas (HOME HOME HOME)":"Leave Khicas (HOME HOME HOME)",TEXT_MODE_NORMAL, COLOR_RED, COLOR_WHITE);
10026       if (confirm("Interpreter? OK: Xcas, Back: MicroPython",(lang==1?"Peut se modifier depuis menu configuration":"May be changed later from menu configuration"),false,130)==KEY_CTRL_F6){
10027 	python_compat(4,contextptr);
10028 	xcas_python_eval=1;
10029 	*logptr(contextptr) << "Micropython interpreter\n";
10030 	Console_FMenu_Init(contextptr);
10031       }
10032       else {
10033 	python_compat(1,contextptr);
10034 	*logptr(contextptr) << "Xcas interpreter, Python compatible mode\n";
10035       }
10036 #endif
10037       Bdisp_AllClr_VRAM();
10038 #ifdef GIAC_SHOWTIME
10039       Console_Output("Reglage de l'heure, exemple");
10040       Console_NewLine(LINE_TYPE_OUTPUT, 1);
10041       Console_Output("12,37=>,");
10042       Console_NewLine(LINE_TYPE_OUTPUT, 1);
10043 #endif
10044       //menu_about();
10045       return 0;
10046     }
10047     return 1;
10048 #endif
10049   }
10050 
extract_name(const char * s)10051   string extract_name(const char * s){
10052     int l=strlen(s),i,j;
10053     for (i=l-1;i>=0;--i){
10054       if (s[i]=='.')
10055 	break;
10056     }
10057     if (i<=0)
10058       return "f";
10059     for (j=i-1;j>=0;--j){
10060       if (s[j]=='\\')
10061 	break;
10062     }
10063     if (j<0)
10064       return "f";
10065     return string(s+j+1).substr(0,i-j-1);
10066   }
10067 
giac_filebrowser(char * filename,const char * extension,const char * title)10068   int giac_filebrowser(char * filename,const char * extension,const char * title){
10069     const char * filenames[MAX_NUMBER_OF_FILENAMES+1];
10070     int n=os_file_browser(filenames,MAX_NUMBER_OF_FILENAMES,extension);
10071     if (n==0) return 0;
10072     int choix=select_item(filenames,title?title:"Scripts");
10073     if (choix<0 || choix>=n) return 0;
10074     strcpy(filename,filenames[choix]);
10075     return choix+1;
10076   }
10077 
erase_script()10078   void erase_script(){
10079     char filename[MAX_FILENAME_SIZE+1];
10080     int res=giac_filebrowser(filename, "py", "Scripts");
10081     if (res && do_confirm((lang==1)?"Vraiment effacer":"Really erase?")){
10082       erase_file(filename);
10083     }
10084   }
10085 
run_script(const char * filename,GIAC_CONTEXT)10086   int run_script(const char* filename,GIAC_CONTEXT) {
10087 #if 0
10088     return 1;
10089 #else
10090     string s;
10091     load_script(filename,s);
10092     // execution_in_progress = 1;
10093     run(s.c_str(),7,contextptr);
10094     // execution_in_progress = 0;
10095     if (s.size()>=4){
10096       if (s[0]=='#' || (s[0]=='d' && s[1]=='e' && s[2]=='f' && s[3]==' '))
10097 	return 2;
10098       if ( (s[0]=='/' && s[1]=='/') ||
10099 	   (s.size()>8 && s[0]=='f' && (s[1]=='o' || s[1]=='u') && s[2]=='n' && s[3]=='c' && s[4]=='t' && s[5]=='i' && s[6]=='o' && s[7]=='n' && s[8]==' ')
10100 	   )
10101 	return 3;
10102     }
10103     return 1;
10104 #endif
10105   }
10106 
edit_script(char * fname,GIAC_CONTEXT)10107   int edit_script(char * fname,GIAC_CONTEXT){
10108     char fname_[MAX_FILENAME_SIZE+1];
10109     char * filename=0;
10110     int res=1;
10111     if (fname)
10112       filename=fname;
10113     else {
10114       res=giac_filebrowser(fname_, "py", "Scripts");
10115       filename=fname_;
10116     }
10117     if(res) {
10118       string s;
10119       load_script(filename,s);
10120       if (s.empty()){
10121 	s=python_compat(contextptr)?((lang==1)?"Prog. Python, sinon taper":"Python prog., for Xcas"):((lang==1)?"Prog. Xcas, sinon taper":"Xcas prog., for Python");
10122 	s += " AC F6 12";
10123 	int k=confirm(s.c_str(),
10124 #ifdef NSPIRE_NEWLIB
10125 		      "enter: Prog, esc: Tortue"
10126 #else
10127 		      "OK: Prog, Back: Tortue"
10128 #endif
10129 		      );
10130 	if (k==-1)
10131 	  return 0;
10132 	if (k==KEY_CTRL_F6)
10133 	  s=python_compat(contextptr)?"from turtle import *\nreset()\n":"\nefface;\n ";
10134 	else
10135 	  s=python_compat(contextptr)?"def "+extract_name(filename)+"(x):\n  \n  return x":"function "+extract_name(filename)+"(x)\nlocal j;\n  \n  return x;\nffunction";
10136       }
10137       // split s at newlines
10138       if (edptr==0)
10139 	edptr=new textArea;
10140       if (!edptr) return -1;
10141       edptr->elements.clear();
10142       edptr->clipline=-1;
10143       edptr->filename=filename;
10144       edptr->editable=true;
10145       edptr->changed=false;
10146       edptr->python=python_compat(contextptr);
10147       edptr->elements.clear();
10148       add(edptr,s);
10149       s.clear();
10150       edptr->line=0;
10151       //edptr->line=edptr->elements.size()-1;
10152       edptr->pos=0;
10153       int res=doTextArea(edptr,contextptr);
10154       if (res==KEY_SHUTDOWN)
10155 	return res;
10156       if (res==-1)
10157 	python_compat(edptr->python,contextptr);
10158       dConsolePutChar('\x1e');
10159     }
10160     return 0;
10161   }
10162 
chk_restart(GIAC_CONTEXT)10163   void chk_restart(GIAC_CONTEXT){
10164     drawRectangle(0, 24, LCD_WIDTH_PX, LCD_HEIGHT_PX-24, COLOR_WHITE);
10165     if (confirm((lang==1)?"Conserver les variables?":"Keep variables?",
10166 #ifdef NSPIRE_NEWLIB
10167 		(lang==1)?"enter: conserver, esc: effacer":"enter: keep, esc: erase"
10168 #else
10169 		(lang==1)?"OK: conserver, Back: effacer":"OK: keep, Back: erase"
10170 #endif
10171 		)==KEY_CTRL_F6)
10172       do_restart(contextptr);
10173   }
10174 
load(GIAC_CONTEXT)10175   void load(GIAC_CONTEXT){
10176     char filename[MAX_FILENAME_SIZE+1];
10177     if (giac_filebrowser(filename, "xw", "Sessions")){
10178       if (console_changed==0 ||
10179 	  strcmp(session_filename,"session")==0 ||
10180 	  confirm((lang==1)?"Session courante perdue?":"Current session will be lost",
10181 #ifdef NSPIRE_NEWLIB
10182 		  (lang==1)?"enter: annul, esc: ok":"enter: cancel, esc: ok"
10183 #else
10184 		  (lang==1)?"OK: annul, Back: ok":"OK: cancel, Back: ok"
10185 #endif
10186 		  )==KEY_CTRL_F6){
10187 	giac::_restart(giac::gen(giac::vecteur(0),giac::_SEQ__VECT),contextptr);
10188 	restore_session(filename,contextptr);
10189 	clip_pasted=true;
10190 	strcpy(session_filename,remove_path(giac::remove_extension(filename)).c_str());
10191 #ifdef NSPIRE_NEWLIB
10192 	static bool ctrl_r=true;
10193 	if (ctrl_r){
10194 	  confirm((lang==1)?"Taper ctrl puis r pour executer session ":"Type ctrl then r to run session","Enter: OK");
10195 	  ctrl_r=false;
10196 	}
10197 #endif
10198 	Console_Disp(0,contextptr);
10199 	// reload_edptr(session_filename,edptr);
10200       }
10201     }
10202   }
10203 
Console_GetKey(GIAC_CONTEXT)10204   int Console_GetKey(GIAC_CONTEXT){
10205     int key;
10206     unsigned int i, move_line, move_col;
10207     char tmp_str[2];
10208     char *tmp;
10209     for (;;){
10210       int keyflag = GetSetupSetting(0x14);
10211       GetKey(&key);
10212       if (key==KEY_SHUTDOWN)
10213 	return key;
10214       bool alph=alphawasactive(&key);
10215       if (key==KEY_PRGM_ACON)
10216 	Console_Disp(1,contextptr);
10217       translate_fkey(key);
10218       if (key==KEY_CTRL_PASTE)
10219 	return Console_Input((const char*) paste_clipboard());
10220       if ( (key==KEY_CHAR_PLUS || key==KEY_CHAR_MINUS || key==KEY_CHAR_MULT || key==KEY_CHAR_DIV) && Current_Line<Last_Line-1){
10221 	console_line * nxt=&Line[Current_Line];
10222 	if (strncmp((const char *)nxt->str,"parameter([",11)==0)
10223 	  Console_MoveCursor(CURSOR_UP);
10224 	nxt=&Line[Current_Line+1];
10225 	if (strncmp((const char *)nxt->str,"parameter([",11)==0){
10226 	  giac::gen g((const char *)nxt->str,contextptr);
10227 	  if (g.is_symb_of_sommet(giac::at_parameter)){
10228 	    g=g._SYMBptr->feuille;
10229 	    if (g.type==giac::_VECT && g._VECTptr->size()>=5){
10230 	      giac::vecteur & v=*g._VECTptr;
10231 	      for (int i=1;i<v.size();++i)
10232 		v[i]=evalf_double(v[i],1,contextptr);
10233 	      if (v[0].type==giac::_IDNT && v[1].type==giac::_DOUBLE_ && v[2].type==giac::_DOUBLE_ && v[3].type==giac::_DOUBLE_ && v[4].type==giac::_DOUBLE_){
10234 		std::string s("assume(");
10235 		s += v[0]._IDNTptr->id_name;
10236 		s += "=[";
10237 		int val=1;
10238 		if (key==KEY_CHAR_MINUS) val=-1;
10239 		if (key==KEY_CHAR_MULT) val=5;
10240 		if (key==KEY_CHAR_DIV) val=-5;
10241 		s += giac::print_DOUBLE_(v[3]._DOUBLE_val + val*v[4]._DOUBLE_val,contextptr);
10242 		s += ',';
10243 		s += giac::print_DOUBLE_(v[1]._DOUBLE_val,contextptr);
10244 		s += ',';
10245 		s += giac::print_DOUBLE_(v[2]._DOUBLE_val,contextptr);
10246 		s += ',';
10247 		s += giac::print_DOUBLE_(v[4]._DOUBLE_val,contextptr);
10248 		s += "])";
10249 		return Console_Eval(s.c_str(),contextptr);
10250 	      }
10251 	    }
10252 	  }
10253 	}
10254       }
10255       if ( (key >= ' ' && key <= '~' )
10256 	   // (key>='0' && key<='9')|| (key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')
10257 	   ){
10258 	tmp_str[0] = key;
10259 	tmp_str[1] = '\0';
10260 	Console_Input(tmp_str);
10261 	Console_Disp(1,contextptr);
10262 	continue;
10263       }
10264       if (key == KEY_CTRL_F5 || key==KEY_EQW_TEMPLATE || key==KEY_CTRL_F4 || ( (key==KEY_CTRL_RIGHT || key==KEY_CTRL_LEFT) && Current_Line<Last_Line) ){
10265 	int l=Current_Line;
10266 	bool graph=strcmp((const char *)Line[l].str,"Graphic object")==0;
10267 	if (graph && l>0) --l;
10268 	char buf[giacmax(512,strlen((const char *)Line[l].str+1))];
10269 	strcpy(buf,(const char *)Line[l].str);
10270 	int ret=(alph || key==KEY_CTRL_RIGHT || key==KEY_CTRL_F4) ?textedit(buf,512,false,contextptr):eqws(buf,graph,contextptr);
10271 	if (ret==KEY_SHUTDOWN)
10272 	  return ret;
10273 	if (ret){
10274 	  if (Current_Line==Last_Line){
10275 	    Console_Clear_EditLine();
10276 	    return Console_Input((const char *)buf);
10277 	  }
10278 	  else {
10279 #if 1
10280 	    if (Line[l].type==LINE_TYPE_INPUT && l<Last_Line-1 && Line[l+1].type==LINE_TYPE_OUTPUT)
10281 	      return Console_Eval(buf,contextptr);
10282 	    else {
10283 	      console_free(Line[l].str);
10284 	      Line[l].str=(char*)console_malloc(strlen(buf)+1);
10285 	      Line[l].disp_len = Console_GetDispLen(Line[l].str);
10286 	      strcpy((char *)Line[l].str,buf);
10287 	    }
10288 #else
10289 	    int x=editline_cursor;
10290 	    move_line = Last_Line - Current_Line;
10291 	    for (i = 0; i <=move_line; i++) Console_MoveCursor(CURSOR_DOWN);
10292 	    Cursor.x=x;
10293 	    return Console_Input((const char *)buf);
10294 #endif
10295 	  }
10296 	}
10297 	Console_Disp(1,contextptr);
10298 	continue;
10299       }
10300       if (0 &&key==KEY_CTRL_F6){
10301 	char buf[512];
10302 	if (!showCatalog(buf,0,0))
10303 	  buf[0]=0;
10304 	return Console_Input((const char*)buf);
10305       }
10306       if (key==KEY_CTRL_S || key==KEY_CTRL_T){
10307 	giac::gen g=sheet(contextptr);
10308 	if (g.type==_INT_ && g.val==KEY_SHUTDOWN)
10309 	  return KEY_SHUTDOWN;
10310 	if (g.type==_VECT)
10311 	  return Console_Input(g.print(contextptr).c_str());
10312 	Console_Disp(1,contextptr);
10313 	continue;
10314       }
10315       if (key==KEY_SAVE){
10316 	save(session_filename,contextptr);
10317 	console_changed=false;
10318 	console_disp_status(contextptr);
10319 	continue;
10320       }
10321       if (key==KEY_LOAD){
10322 	load(contextptr);
10323 	Console_Disp(1,contextptr);
10324 	continue;
10325       }
10326       if (key==KEY_CTRL_MENU){
10327 #if 1
10328 	Menu smallmenu;
10329 	smallmenu.numitems=17;
10330 	MenuItem smallmenuitems[smallmenu.numitems];
10331 
10332 	smallmenu.items=smallmenuitems;
10333 	smallmenu.height=12;
10334 	smallmenu.scrollbar=1;
10335 	smallmenu.scrollout=1;
10336 	//smallmenu.title = "KhiCAS";
10337 	// smallmenuitems[2].text = (char*)(isRecording ? "Stop Recording" : "Record Script");
10338 	while(1) {
10339 	  // moved inside the loop because lang might change
10340 	  smallmenuitems[0].text = (char*)"Applications (shift ANS)";
10341 	  smallmenuitems[1].text = (char *) ((lang==1)?"Enregistrer session":"Save session ");
10342 	  smallmenuitems[2].text = (char *) ((lang==1)?"Enregistrer sous":"Save session as");
10343 	  if (exam_mode)
10344 	    smallmenuitems[2].text = (char *) "";
10345 	  smallmenuitems[3].text = (char*) ((lang==1)?"Charger session":"Load session");
10346 	  smallmenuitems[4].text = (char*)((lang==1)?"Nouvelle session":"New session");
10347 	  smallmenuitems[5].text = (char*)((lang==1)?"Executer session":"Run session");
10348 	  smallmenuitems[6].text = (char*)((lang==1)?"Editeur script":"Script editor");
10349 	  smallmenuitems[7].text = (char*)((lang==1)?"Ouvrir script":"Open script");
10350 	  smallmenuitems[8].text = (char*)((lang==1)?"Executer script":"Run script");
10351 	  smallmenuitems[9].text = (char*)((lang==1)?"Effacer historique (0)":"Clear history");
10352 	  smallmenuitems[10].text = (char*)((lang==1)?"Effacer script (e^)":"Clear script");
10353 	  smallmenuitems[11].text = (char*)"Configuration/examen (ln)";
10354 	  smallmenuitems[12].text = (char *) ((lang==1)?"Aide interface (log)":"Shortcuts");
10355 	  smallmenuitems[13].text = (char*)((lang==1)?"Editer matrice (i)":"Matrix editor");
10356 	  smallmenuitems[14].text = (char*) ((lang==1)?"Creer parametre (,)":"Create slider (,)");
10357 	  smallmenuitems[15].text = (char*) ((lang==1)?"A propos (x^y)":"About");
10358 #ifdef NSPIRE_NEWLIB
10359 	  smallmenuitems[16].text = (char*) ((lang==1)?"Quitter (menu)":"Quit");
10360 #else
10361 	  smallmenuitems[16].text = (char*) ((lang==1)?"Quitter (HOME)":"Quit");
10362 #endif
10363 	  if (exam_mode)
10364 	    smallmenuitems[16].text = (char*)((lang==1)?"Quitter le mode examen":"Quit exam mode");
10365 	  int sres = doMenu(&smallmenu);
10366 	  if(sres == MENU_RETURN_SELECTION || sres==KEY_CTRL_EXE) {
10367 	    if (smallmenu.selection==smallmenu.numitems){
10368 	      if (!exam_mode)
10369 		return KEY_CTRL_MENU;
10370 	      leave_exam_mode(contextptr);
10371 	      break;
10372 	    }
10373 	    const char * ptr=0;
10374 	    if (smallmenu.selection==1){
10375 	      key=KEY_SHIFT_ANS;
10376 	      break;
10377 	    }
10378 	    if (smallmenu.selection==2){
10379 	      if (strcmp(session_filename,"session")==0)
10380 		smallmenu.selection=3;
10381 	      else {
10382 		save(session_filename,contextptr);
10383 		break;
10384 	      }
10385 	    }
10386 	    if (smallmenu.selection==3 && !exam_mode){
10387 	      char buf[270];
10388 	      if (get_filename(buf,".xw")){
10389 		save(buf,contextptr);
10390 		string fname(remove_path(giac::remove_extension(buf)));
10391 		strcpy(session_filename,fname.c_str());
10392 		if (edptr)
10393 		  edptr->filename=fname+".py";
10394 	      }
10395 	      break;
10396 	    }
10397 	    if (smallmenu.selection==4){
10398 	      load(contextptr);
10399 	      break;
10400 	    }
10401 	    if (0 && smallmenu.selection==5) {
10402 	      // FIXME: make a menu catalog?
10403 	      char buf[512];
10404 	      if (doCatalogMenu(buf,(char*)"CATALOG",0,contextptr))
10405 		return Console_Input((const char *)buf);
10406 	      break;
10407 	    }
10408 	    if (smallmenu.selection==5) {
10409 	      if (exam_mode){
10410 		if (do_confirm((lang==1)?"Tout effacer?":"Really clear?")){
10411 		  Console_Init(contextptr);
10412 		  Console_Clear_EditLine();
10413 		  giac::_restart(giac::gen(giac::vecteur(0),giac::_SEQ__VECT),contextptr);
10414 		}
10415 	      }
10416 	      else {
10417 		char filename[MAX_FILENAME_SIZE+1];
10418 		drawRectangle(0, 0, LCD_WIDTH_PX, LCD_HEIGHT_PX, COLOR_WHITE);
10419 		if (get_filename(filename,".xw")){
10420 		  if (console_changed==0 ||
10421 		      strcmp(session_filename,"session")==0 ||
10422 		      confirm((lang==1)?"Session courante perdue?":"Current session will be lost",
10423 #ifdef NSPIRE_NEWLIB
10424 			      (lang==1)?"enter: annul, esc: ok":"enter: cancel, esc: ok"
10425 #else
10426 			      (lang==1)?"OK: annul, Back: ok":"OK: cancel, Back: ok"
10427 #endif
10428 			      )==KEY_CTRL_F6){
10429 		    clip_pasted=true;
10430 		    Console_Init(contextptr);
10431 		    Console_Clear_EditLine();
10432 		    giac::_restart(giac::gen(giac::vecteur(0),giac::_SEQ__VECT),contextptr);
10433 		    std::string s(remove_path(giac::remove_extension(filename)));
10434 		    strcpy(session_filename,s.c_str());
10435 		    reload_edptr(session_filename,edptr,contextptr);
10436 		  }
10437 		}
10438 	      }
10439 	      break;
10440 	    }
10441 	    if (smallmenu.selection==6) {
10442 	      run_session(0,contextptr);
10443 	      break;
10444 	    }
10445 	    if (smallmenu.selection==7) {
10446 	      if (!edptr || merge_area(edptr->elements).size()<2)
10447 		edit_script((char *)(giac::remove_extension(session_filename)+".py").c_str(),contextptr);
10448 	      else
10449 		doTextArea(edptr,contextptr);
10450 	      break;
10451 	    }
10452 	    if (smallmenu.selection==8) {
10453 	      char filename[MAX_FILENAME_SIZE+1];
10454 	      drawRectangle(0, 0, LCD_WIDTH_PX, LCD_HEIGHT_PX-8, COLOR_WHITE);
10455 	      if (giac_filebrowser(filename, "py", "Scripts"))
10456 		edit_script(filename,contextptr);
10457 	      break;
10458 	    }
10459 	    if (smallmenu.selection==9) {
10460 	      char filename[MAX_FILENAME_SIZE+1];
10461 	      drawRectangle(0, 0, LCD_WIDTH_PX, LCD_HEIGHT_PX-8, COLOR_WHITE);
10462 	      if (giac_filebrowser(filename, "py", "Scripts"))
10463 		run_script(filename,contextptr);
10464 	      Console_Clear_EditLine();
10465 	      break;
10466 	    }
10467 	    if(smallmenu.selection == 10) {
10468 	      chk_restart(contextptr);
10469 	      Console_Init(contextptr);
10470 	      Console_Clear_EditLine();
10471 	      break;
10472 	    }
10473 	    if (smallmenu.selection==11){
10474 	      erase_script();
10475 	      break;
10476 	    }
10477 	    if (smallmenu.selection == 12){
10478 	      menu_setup(contextptr);
10479 	      continue;
10480 	    }
10481 	    if(smallmenu.selection == 13 ||smallmenu.selection == 16 ) {
10482 	      textArea text;
10483 	      text.editable=false;
10484 	      text.clipline=-1;
10485 	      text.title = smallmenuitems[smallmenu.selection-1].text;
10486 	      add(&text,smallmenu.selection==13?((lang==1)?shortcuts_fr_string:shortcuts_en_string):((lang==1)?apropos_fr_string:apropos_en_string));
10487 	      doTextArea(&text,contextptr);
10488 	      continue;
10489 	    }
10490 	    if (smallmenu.selection==14){
10491 	      drawRectangle(0, 0, LCD_WIDTH_PX, LCD_HEIGHT_PX-8, COLOR_WHITE);
10492 	      if (ptr=input_matrix(false,contextptr)) {
10493 		return Console_Input((const char *)ptr);
10494 	      }
10495 	      break;
10496 	    }
10497 	    if (smallmenu.selection == 15){
10498 	      Menu paramenu;
10499 	      paramenu.numitems=6;
10500 	      MenuItem paramenuitems[paramenu.numitems];
10501 	      paramenu.items=paramenuitems;
10502 	      paramenu.height=12;
10503 	      paramenu.title = (char *)"Parameter";
10504 	      char menu_xcur[32],menu_xmin[32],menu_xmax[32],menu_xstep[32],menu_name[16]="name a";
10505 	      static char curname='a';
10506 	      menu_name[5]=curname;
10507 	      ++curname;
10508 	      double pcur=0,pmin=-5,pmax=5,pstep=0.1;
10509 	      std::string s;
10510 	      bool doit;
10511 	      for (;;){
10512 		s="cur "+giac::print_DOUBLE_(pcur,contextptr);
10513 		strcpy(menu_xcur,s.c_str());
10514 		s="min "+giac::print_DOUBLE_(pmin,contextptr);
10515 		strcpy(menu_xmin,s.c_str());
10516 		s="max "+giac::print_DOUBLE_(pmax,contextptr);
10517 		strcpy(menu_xmax,s.c_str());
10518 		s="step "+giac::print_DOUBLE_(pstep,contextptr);
10519 		strcpy(menu_xstep,s.c_str());
10520 		paramenuitems[0].text = (char *) "OK";
10521 		paramenuitems[1].text = (char *) menu_name;
10522 		paramenuitems[2].text = (char *) menu_xcur;
10523 		paramenuitems[3].text = (char *) menu_xmin;
10524 		paramenuitems[4].text = (char *) menu_xmax;
10525 		paramenuitems[5].text = (char *) menu_xstep;
10526 		int sres = doMenu(&paramenu);
10527 		doit = sres==MENU_RETURN_SELECTION  || sres==KEY_CTRL_EXE;
10528 		if (doit) {
10529 		  std::string s1; double d;
10530 		  if (paramenu.selection==2){
10531 		    handle_f5();
10532 		    if (inputline(menu_name,(lang==1)?"Nouvelle valeur?":"New value?",s1,false)==KEY_CTRL_EXE && s1.size()>0 && isalpha(s1[0])){
10533 		      if (s1.size()>10)
10534 			s1=s1.substr(0,10);
10535 		      strcpy(menu_name,("name "+s1).c_str());
10536 		    }
10537 		    continue;
10538 		  }
10539 		  if (paramenu.selection==3){
10540 		    inputdouble(menu_xcur,pcur,contextptr);
10541 		    continue;
10542 		  }
10543 		  if (paramenu.selection==4){
10544 		    inputdouble(menu_xmin,pmin,contextptr);
10545 		    continue;
10546 		  }
10547 		  if (paramenu.selection==5){
10548 		    inputdouble(menu_xmax,pmax,contextptr);
10549 		    continue;
10550 		  }
10551 		  if (paramenu.selection==6){
10552 		    inputdouble(menu_xstep,pstep,contextptr);
10553 		    pstep=fabs(pstep);
10554 		    continue;
10555 		  }
10556 		  // if (paramenu.selection==6) break;
10557 		} // end menu
10558 		break;
10559 	      } // end for (;;)
10560 	      if (doit && pmin<pmax && pstep>0){
10561 		s="assume(";
10562 		s += (menu_name+5);
10563 		s += "=[";
10564 		s += (menu_xcur+4);
10565 		s += ',';
10566 		s += (menu_xmin+4);
10567 		s += ',';
10568 		s += (menu_xmax+4);
10569 		s += ',';
10570 		s += (menu_xstep+5);
10571 		s += "])";
10572 		return Console_Input((const char *)s.c_str());
10573 	      }
10574 	      continue;
10575 	    }
10576 	  }
10577 	  break;
10578 	} // end while(1)
10579 	if (key!=KEY_SHIFT_ANS){
10580 	  Console_Disp(1,contextptr);
10581 	  return CONSOLE_SUCCEEDED;
10582 	}
10583 #else
10584 	char filename[MAX_FILENAME_SIZE+1];
10585 	//drawRectangle(0, 24, LCD_WIDTH_PX, LCD_HEIGHT_PX-24, COLOR_WHITE);
10586 	if (get_filename(filename))
10587 	  edit_script(filename,contextptr);
10588 	//edit_script(0);
10589 	return CONSOLE_SUCCEEDED;
10590 #endif
10591       }
10592       if (key==KEY_SHIFT_ANS){ // 3rd party app
10593 	int res=khicas_addins_menu(contextptr);
10594 	if (res==KEY_CTRL_MENU)
10595 	  return res;
10596 	Console_Disp(1,contextptr);
10597 	return CONSOLE_SUCCEEDED;
10598       }
10599       if ( (key >= KEY_CTRL_F1 && key <= KEY_CTRL_F6) ||
10600 	   (key >= KEY_CTRL_F7 && key <= KEY_CTRL_F14)
10601 	   ){
10602 	return Console_FMenu(key,contextptr);
10603       }
10604       if (key == KEY_CTRL_UP)
10605 	return Console_MoveCursor(alph?CURSOR_ALPHA_UP:CURSOR_UP);
10606       if (key == KEY_CTRL_DOWN || key=='\t'
10607 	  // FIREBIRDEMU
10608 	  || key==KEY_BOOK
10609 	  ){
10610 	if (Current_Line==Last_Line && !Line[Current_Line].readonly && Current_Col>0){
10611 	  char buf[strlen(Edit_Line)+1];
10612 	  strcpy(buf,Edit_Line);
10613 	  buf[Cursor.x]=0;
10614 	  string s=help_insert(buf,contextptr);
10615 	  Console_Input(s.c_str());
10616 	  Console_Disp(1,contextptr);
10617 	  Console_MoveCursor(CURSOR_SHIFT_RIGHT);
10618 	  continue;
10619 	}
10620 	return Console_MoveCursor(alph?CURSOR_ALPHA_DOWN:CURSOR_DOWN);
10621       }
10622       //if (key == KEY_CTRL_PAGEUP)  return Console_MoveCursor(CURSOR_ALPHA_UP);
10623       //if (key == KEY_CTRL_PAGEDOWN) return Console_MoveCursor(CURSOR_ALPHA_DOWN);
10624       if (key == KEY_CTRL_LEFT)
10625 	Console_MoveCursor(CURSOR_LEFT);
10626       if (key == KEY_CTRL_RIGHT)
10627 	Console_MoveCursor(CURSOR_RIGHT);
10628       if (key == KEY_SHIFT_LEFT)
10629 	Console_MoveCursor(CURSOR_SHIFT_LEFT);
10630       if (key == KEY_SHIFT_RIGHT)
10631 	Console_MoveCursor(CURSOR_SHIFT_RIGHT);
10632       if (key == KEY_SHIFT_RIGHT || key == KEY_SHIFT_LEFT ||
10633 	  key == KEY_CTRL_RIGHT || key == KEY_CTRL_LEFT){
10634 	Console_Disp(0,contextptr);
10635 	continue;
10636       }
10637       if (key == KEY_CTRL_EXIT){
10638 	if (Last_Line==Current_Line){
10639 	  if (!edptr)
10640 	    edit_script((char *)(giac::remove_extension(session_filename)+".py").c_str(),contextptr);
10641 	  else {
10642 	    edptr->y=0;
10643 	    doTextArea(edptr,contextptr);
10644 	  }
10645 	  Console_Disp(1,contextptr);
10646 	}
10647 	else {
10648 	  move_line = Last_Line - Current_Line;
10649 	  for (i = 0; i <= move_line; i++) Console_MoveCursor(CURSOR_DOWN);
10650 	}
10651 	return CONSOLE_SUCCEEDED;
10652       }
10653       if (key == KEY_CTRL_AC)
10654 	{
10655 	  if (Line[Current_Line].readonly){
10656 	    move_line = Last_Line - Current_Line;
10657 	    for (i = 0; i <= move_line; i++) Console_MoveCursor(CURSOR_DOWN);
10658 	    return CONSOLE_SUCCEEDED;
10659 	  }
10660 	  if (Edit_Line[0]=='\0'){
10661 	    //return Console_Input((const char *)"restart");
10662 	    chk_clearscreen(contextptr);
10663 	    continue;
10664 	  }
10665 	  Edit_Line[0] = '\0';
10666 	  Line[Current_Line].start_col = 0;
10667 	  Line[Current_Line].type = LINE_TYPE_INPUT;
10668 	  Line[Current_Line].disp_len = 0;
10669 	  Cursor.x = 0;
10670 	  return CONSOLE_SUCCEEDED;
10671 	}
10672 
10673       if (key == KEY_CTRL_INS) {
10674 	if (Current_Line<Last_Line){
10675 	  Console_Insert_Line();
10676 	  Console_Insert_Line();
10677 	}
10678 	else
10679 	  Console_Input((const char*)":=");
10680 	Console_Disp(1,contextptr);
10681 	continue;
10682       }
10683       if (key==KEY_AFFECT){
10684 	Console_Input((const char*)":=");
10685 	Console_Disp(1,contextptr);
10686 	continue;
10687       }
10688       if (key==KEY_CTRL_D){
10689 	Console_Input((const char*)"debug(");
10690 	Console_Disp(1,contextptr);
10691 	continue;
10692       }
10693       if (key == KEY_CTRL_SETUP) {
10694 	menu_setup(contextptr);
10695 	Console_Disp(1,contextptr);
10696 	continue;
10697       }
10698 
10699       if (key == KEY_CTRL_EXE || key==KEY_CTRL_OK){
10700 	if (Current_Line == Last_Line)
10701 	  {
10702 	    return Console_NewLine(LINE_TYPE_INPUT, 1);
10703 	  }
10704       }
10705       if (key == KEY_CTRL_DEL)
10706 	return Console_Backspace(contextptr);
10707       if (key == KEY_CTRL_R){
10708 	run_session(0,contextptr);
10709 	return 0;
10710       }
10711       if (key == KEY_CTRL_CLIP){
10712 	copy_clipboard((const char *)Line[Current_Line].str,true);
10713       }
10714       if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK){
10715 	tmp = Line[Current_Line].str;
10716 
10717 #if 1
10718 	int x=editline_cursor;
10719 	move_line = Last_Line - Current_Line;
10720 	for (i = 0; i <= move_line; i++) Console_MoveCursor(CURSOR_DOWN);
10721 	Cursor.x=x;
10722 	if (Cursor.x>COL_DISP_MAX)
10723 	  Line[Last_Line].start_col=Cursor.x-COL_DISP_MAX;
10724 #else
10725 	move_line = Last_Line - Current_Line;
10726 	for (i = 0; i <= move_line; i++) Console_MoveCursor(CURSOR_DOWN);
10727 	move_col = Line[Current_Line].disp_len - Current_Col;
10728 	for (i = 0; i <= move_col; i++) Console_MoveCursor(CURSOR_RIGHT);
10729 #endif
10730 	return Console_Input(tmp);
10731       }
10732       const char * ptr=keytostring(key,keyflag,0,contextptr);
10733       if (ptr)
10734 	return Console_Input((const char *)ptr);
10735 
10736     }
10737     return CONSOLE_NO_EVENT;
10738   }
10739 
Console_FMenu(int key,GIAC_CONTEXT)10740   int Console_FMenu(int key,GIAC_CONTEXT){
10741     const char * s=console_menu(key,fmenu_cfg,0),*ptr=0;
10742     if (!s){
10743       //cout << "console " << unsigned(s) << endl;
10744       return CONSOLE_NO_EVENT;
10745     }
10746     if (strcmp("matrix(",s)==0 && (ptr=input_matrix(false,contextptr)) )
10747       s=ptr;
10748     if (strcmp("makelist(",s)==0 && (ptr=input_matrix(true,contextptr)) )
10749       s=ptr;
10750     return Console_Input((const char *)s);
10751   }
10752 
console_menu(int key,int active_app)10753   const char * console_menu(int key,int active_app){
10754     return console_menu(key,fmenu_cfg,active_app);
10755   }
10756 
console_menu(int key,char * cfg_,int active_app)10757   const char * console_menu(int key,char* cfg_,int active_app){
10758     char * cfg=cfg_;
10759     int i, matched = 0;
10760     const char * ret=0;
10761     const int maxentry_size=64;
10762     static char console_buf[maxentry_size];
10763     char temp[maxentry_size],menu1[maxentry_size],menu2[maxentry_size],menu3[maxentry_size],menu4[maxentry_size],menu5[maxentry_size],menu6[maxentry_size],menu7[maxentry_size],menu8[maxentry_size];
10764     char * tabmenu[8]={menu1,menu2,menu3,menu4,menu5,menu6,menu7,menu8};
10765     struct FMenu entry = {0,tabmenu,0};
10766     // char* cfg = (char *)memory_load((char *)"\\\\fls0\\FMENU.cfg");
10767 
10768     while (*cfg) {
10769       //Get each line
10770       for(i=0; i<maxentry_size-1 && *cfg && *cfg!='\r' && *cfg!='\n'; i++, cfg++) {
10771 	temp[i] = *cfg;
10772       }
10773       temp[i]=0;
10774       //If starting by 'F' followed by the right number, start filling the structure.
10775       if (temp[0] == 'F' && temp[1]==(key-KEY_CTRL_F1)+'1'){
10776 	matched = 1;
10777 	continue;
10778       }
10779       if (temp[0] == 'F' && temp[1]!=(key-KEY_CTRL_F1)+'0'){
10780 	matched = 0;
10781 	continue;
10782       }
10783       //Fill the structure
10784       if (matched && temp[0] && entry.count<8) {
10785 	strcpy(tabmenu[entry.count], temp);
10786 	entry.count++;
10787       }
10788       cfg++;
10789     }
10790     if(entry.count > 0) {
10791       ret = Console_Draw_FMenu(key, &entry,cfg,active_app);
10792       // cout << "console0 " << (unsigned) ret << endl;
10793       if (!ret) return ret;
10794       if (!strcmp("periodic_table",ret)){
10795 	const char * name,*symbol;
10796 	char protons[32],nucleons[32],mass[32],electroneg[32];
10797 	int res=periodic_table(name,symbol,protons,nucleons,mass,electroneg);
10798 	if (!res)
10799 	  return 0;
10800 	char * ptr=console_buf;
10801 	if (res & 1)
10802 	  ptr=strcpy(ptr,name)+strlen(ptr);
10803 	if (res & 2){
10804 	  if (res & 1)
10805 	    ptr=strcpy(ptr,",")+strlen(ptr);
10806 	  ptr=strcpy(ptr,symbol)+strlen(ptr);
10807 	}
10808 	if (res & 4){
10809 	  if (res&3)
10810 	    ptr=strcpy(ptr,",")+strlen(ptr);
10811 	  ptr=strcpy(ptr,protons)+strlen(ptr);
10812 	}
10813 	if (res & 8){
10814 	  if (res&7)
10815 	    ptr=strcpy(ptr,",")+strlen(ptr);
10816 	  ptr=strcpy(ptr,nucleons)+strlen(ptr);
10817 	}
10818 	if (res & 16){
10819 	  if (res&15)
10820 	    ptr=strcpy(ptr,",")+strlen(ptr);
10821 	  ptr=strcpy(ptr,mass+2)+strlen(ptr);
10822 	}
10823 	if (res & 32){
10824 	  if (res&31)
10825 	    ptr=strcpy(ptr,",")+strlen(ptr);
10826 	  ptr=strcpy(ptr,electroneg+4)+strlen(ptr);
10827 	}
10828       }
10829       else
10830 	strcpy(console_buf,ret);
10831       return console_buf;
10832     }
10833     return 0;
10834   }
10835 
Console_Make_Entry(const char * str)10836   char *Console_Make_Entry(const char* str)
10837   {
10838     char* entry = NULL;
10839     entry = (char*)calloc((strlen((const char *)str)+1), sizeof(char*));
10840     if(entry) memcpy(entry, (const char *)str, strlen((const char *)str)+1);
10841 
10842     return entry;
10843   }
10844 
PrintMini(int x,int y,const char * s,int mode)10845   void PrintMini(int x,int y,const char * s,int mode){
10846     x *=3;
10847     y *=3;
10848     PrintMini(x,y,(char *)s,mode,COLOR_BLACK, COLOR_WHITE);
10849   }
10850 
10851   //Draws and runs the asked for menu.
Console_Draw_FMenu(int key,struct FMenu * menu,char * cfg,int active_app)10852   const char * Console_Draw_FMenu(int key, struct FMenu* menu,char * cfg,int active_app)
10853   {
10854     int i, nb_entries = 0, selector = 0, position_number, position_x, ret, longest = 0;
10855     int input_key;
10856     char quick[] = "*: ";
10857     int quick_len = 2;
10858     char **entries;
10859     DISPBOX box,box3;
10860 
10861     position_number = key - KEY_CTRL_F1;
10862     if (position_number<0 || position_number>=5)
10863       position_number=4;
10864 
10865     entries  = menu->str;
10866     nb_entries = menu->count;
10867 
10868     for(i=0; i<nb_entries; i++)
10869       if(strlen(entries[i]) > longest) longest = strlen(entries[i]);
10870     if (longest>15)
10871       longest=15;
10872     // screen resolution Graph90 384x(216-24), Graph35 128x64
10873     // factor 3x3
10874     position_x = 17*position_number;
10875     if(position_x + longest*4 + quick_len*4 > 115) position_x = 115 - longest*4 - quick_len*4;
10876 
10877     box.left = position_x;
10878     box.right = position_x + longest*4 + quick_len*4  + 6;
10879     box.bottom = 63-7;
10880     box.top = 63-7-nb_entries*7;
10881     box3.left=3*box.left;
10882     box3.right=3*box.right;
10883     box3.bottom=3*box.bottom+22;
10884     box3.top=3*box.top+20;
10885 
10886     drawRectangle(box3.left,box3.top,box3.right-box3.left,box3.bottom-box3.top,COLOR_WHITE);
10887     drawLine(box3.left, box3.top, box3.right, box3.top,COLOR_BLACK);
10888     drawLine(box3.left, box3.bottom, box3.left, box3.top,COLOR_BLACK);
10889     drawLine(box3.right, box3.bottom, box3.right, box3.top,COLOR_BLACK);
10890     drawLine(box3.left, box3.bottom, box3.right, box3.bottom,COLOR_BLACK);
10891 
10892     // Cursor_SetFlashOff();
10893 
10894     for (;;){
10895       for(i=0; i<nb_entries; i++) {
10896 	quick[0] = '0'+(i+1);
10897 	PrintMini(3+position_x, box.bottom-7*i, quick, 0);
10898 	PrintMini(3+position_x+quick_len*4, box.bottom-7*i, entries[i], 0);
10899       }
10900       PrintMini(3+position_x+quick_len*4,box.bottom-7*selector, entries[selector], 4);
10901       GetKey(&input_key);
10902       if (input_key==KEY_PRGM_ACON) Console_Disp(1,0);
10903       if (input_key == KEY_CTRL_EXIT || input_key==KEY_CTRL_AC) return 0;
10904       if (input_key == KEY_CTRL_UP && selector < nb_entries-1) selector++;
10905       if (input_key == KEY_CTRL_DOWN && selector > 0) selector--;
10906 
10907       if (input_key == KEY_CTRL_EXE || input_key==KEY_CTRL_OK) return entries[selector];
10908 
10909       if (input_key >= KEY_CHAR_1 && input_key < KEY_CHAR_1 + nb_entries) return entries[input_key-KEY_CHAR_1];
10910 
10911       translate_fkey(input_key);
10912 
10913       if ( active_app==0 &&
10914 	   ((input_key >= KEY_CTRL_F1 && input_key <= KEY_CTRL_F6) ||
10915 	    (input_key >= KEY_CTRL_F7 && input_key <= KEY_CTRL_F12) )
10916 	   ){
10917 	Console_Disp(1,0);
10918 	key=input_key;
10919 	return console_menu(key,cfg,active_app);
10920       }
10921     } // end while input_key!=EXE/EXIT
10922 
10923     return 0; // never reached
10924   }
10925 
Console_Free()10926   void Console_Free(){
10927     for (int i = 0; i < _LINE_MAX; i++){
10928       if (Line[i].str){
10929 	if (Line[i].str==Edit_Line)
10930 	  Edit_Line=0;
10931 	console_free(Line[i].str);
10932 	Line[i].str=0;
10933       }
10934     }
10935     if (Edit_Line)
10936       console_free(Edit_Line);
10937     if (Line){
10938       delete [] Line;
10939       Line = 0;
10940     }
10941   }
10942 
Console_Init(GIAC_CONTEXT)10943   int Console_Init(GIAC_CONTEXT){
10944     console_changed=1;
10945     int i;
10946     if (!Line){
10947       Line=new console_line[_LINE_MAX];
10948       for (i = 0; i < _LINE_MAX; i++){
10949 	Line[i].str=0;
10950       }
10951     }
10952     Start_Line = 0;
10953     Last_Line = 0;
10954 
10955     for (i = 0; i < _LINE_MAX; i++){
10956       if (Line[i].str){
10957 	if (Line[i].str==Edit_Line)
10958 	  Edit_Line=0;
10959 	console_free(Line[i].str);
10960 	Line[i].str=0;
10961       }
10962       Line[i].readonly = 0;
10963       Line[i].type = LINE_TYPE_INPUT;
10964       Line[i].start_col = 0;
10965       Line[i].disp_len = 0;
10966     }
10967     if (Edit_Line)
10968       console_free(Edit_Line);
10969     if ((Edit_Line = (char *)console_malloc(EDIT_LINE_MAX + 1)) == NULL) return CONSOLE_MEM_ERR;
10970     Edit_Line[0]=0;
10971     Line[0].str = Edit_Line;
10972 
10973     Cursor.x = 0;
10974     Cursor.y = 0;
10975 
10976     Case = LOWER_CASE;
10977 
10978     /*for(i = 0; i < 6; i++) {
10979       FMenu_entries[i].name = NULL;
10980       FMenu_entries[i].count = 0;
10981       }*/
10982 
10983     Console_FMenu_Init(contextptr);
10984 
10985     return CONSOLE_SUCCEEDED;
10986   }
10987 
10988   const char conf_standard[] = "F1 algb\nsimplify(\nfactor(\npartfrac(\ntcollect(\ntexpand(\nsum(\noo\nproduct(\nF2 calc\n'\ndiff(\nintegrate(\nlimit(\nseries(\nsolve(\ndesolve(\nrsolve(\nF5  2d \nreserved\nF4 menu\nreserved\nF6 reg\nlinear_regression_plot(\nlogarithmic_regression_plot(\nexponential_regression_plot(\npower_regression_plot(\npolynomial_regression_plot(\nsin_regression_plot(\nscatterplot(\nmatrix(\nF= poly\nproot(\npcoeff(\nquo(\nrem(\ngcd(\negcd(\nresultant(\nGF(\nF9 arit\n mod \nirem(\nifactor(\ngcd(\nisprime(\nnextprime(\npowmod(\niegcd(\nF7 lin\nmatrix(\ndet(\nmatpow(\nranm(\nrref(\ntran(\negvl(\negv(\nF8 list\nmakelist(\nrange(\nseq(\nlen(\nappend(\nranv(\nsort(\napply(\nF3 plot\nplot(\nplotseq(\nplotlist(\nplotparam(\nplotpolar(\nplotfield(\nhistogram(\nbarplot(\nF; real\nexact(\napprox(\nfloor(\nceil(\nround(\nsign(\nmax(\nmin(\nF< prog\n:\n&\n#\nhexprint(\nbinprint(\nf(x):=\ndebug(\npython(\nF> cplx\nabs(\narg(\nre(\nim(\nconj(\ncsolve(\ncfactor(\ncpartfrac(\nF= misc\n!\nrand(\nbinomial(\nnormald(\nexponentiald(\n\\\n % \nperiodic_table\n";
10989 
10990   const char python_conf_standard[] = "F1 misc\n\"\n\'\n;\n:\n[]\ndef f(x):return\ncaseval(\"\nfrom cas import *\nF2 math\nfloor(\nceil(\nround(\nmin(\nmax(\nsign(\nsqrt(\nfrom math import *\nF3 rand\nrandint(\nrandom()\nchoice(\nfrom random import *\nF4 menu\nreserved\nF5  2d\nreserved\nF; color\n\nF6 tortue\nforward(\nbackward(\nleft(\nright(\npencolor(\ncircle(\nreset()\nfrom turtle import *\nF9 plot\nplot(\ntext(\narrow(\nlinear_regression_plot(\nscatter(\naxis(\nbar(\nfrom matplotl import *\nF7 linalg\nmatrix(\nadd(\nsub(\nmul(\ninv(\nrref(\ntranspose(\nfrom linalg import *\nF8 list\nlist(\nrange(\nlen(\nappend(\nhead(\nsort(\napply(\nF: color\nred\nblue\ngreen\ncyan\nyellow\nmagenta\nblack\nwhite\nF< prog\n:\n&\n#\nhexprint(\nbinprint(\nf(x):=\ndebug(\npython(\nF> cplx\nabs(\narg(\nre(\nim(\nconj(\npolar(\nrect(\nfrom cmath import *\nF= draw\nclear_screen();\nshow_screen();\nset_pixel(\ndraw_line(\ndraw_rectangle(\n\ndraw_circle(\ndraw_string(\nfrom graphic import *\n";
10991 
10992   // Loads the FMenus' data into memory, from a cfg file
Console_FMenu_Init(GIAC_CONTEXT)10993   void Console_FMenu_Init(GIAC_CONTEXT)
10994   {
10995     char temp[32] = {'\0'};
10996 #if 0
10997     if (!fmenu_cfg){
10998       fmenu_cfg = (char *)conf_standard;
10999       std::string cfg_s;
11000       // Does the file exists ?
11001       if (load_script((char*)"FMENU.cfg",cfg_s)){
11002 	char * ptr=new char[cfg_s.size()+1];
11003 	strcpy(ptr,cfg_s.c_str());
11004 	fmenu_cfg=(char *)ptr;
11005       }
11006       if(!fmenu_cfg) {
11007 	save_script((const char *)"FMENU.cfg",conf_standard);
11008 	fmenu_cfg = (char *)conf_standard;
11009       }
11010     }
11011 #else
11012     if (xcas_python_eval==1){
11013       fmenu_cfg=(char *)python_conf_standard;
11014     }
11015     else {
11016       fmenu_cfg=(char *)conf_standard;
11017     }
11018 #endif
11019     const char *cfg=fmenu_cfg;
11020     while(*cfg) {
11021       //Get each line
11022       int i;
11023       for(i=0; i<20 && *cfg && *cfg!='\r' && *cfg!='\n'; i++, cfg++) {
11024 	temp[i] = *cfg;
11025       }
11026       temp[i]=0;
11027       //If starting by 'F', adjust the number and eventually set the name of the menu
11028       if(temp[0] == 'F' && temp[1]>='1' && temp[1]<='6') {
11029 	int number = temp[1]-'0' - 1;
11030 	if(temp[3] && number<6) {
11031 	  strcpy(FMenu_entries_name[number], (char*)temp+3);
11032 	  //FMenu_entries[number].name[4] = '\0';
11033 	}
11034       }
11035 
11036       memset(temp, '\0', 20);
11037       cfg++;
11038     }
11039     //free(fmenu_cfg);
11040   }
11041 
11042   /*
11043     The following functions are used to display all lines.
11044     Note: After calling this function, the first clear the memory.
11045   */
11046 
11047 #ifndef CURSOR
11048   int print_x=0,print_y=0,vfontsize=18,hfontsize=12;
11049 #endif
11050 
locate(int x,int y)11051   void locate(int x,int y){
11052 #ifdef CURSOR
11053     return locate_OS(x,y);
11054 #else
11055     print_x=(x-1)*hfontsize;
11056     print_y=(y-1)*vfontsize;
11057 #endif
11058   }
11059 
Cursor_SetPosition(int x,int y)11060   void Cursor_SetPosition(int x,int y){
11061     return locate(x+1,y+1);
11062   }
11063 
PrintRev(const char * s,int color=TEXT_COLOR_BLACK)11064   void PrintRev(const char * s,int color=TEXT_COLOR_BLACK){
11065 #ifdef CURSOR
11066     Print_OS((char *)s,TEXT_MODE_INVERT,0);
11067 #else
11068     print(print_x,print_y,(const char *)s,color,true/* revert*/,false,false);
11069 #endif
11070   }
11071 
Print(const char * s,int color=TEXT_COLOR_BLACK)11072   void Print(const char * s,int color=TEXT_COLOR_BLACK){
11073 #ifdef CURSOR
11074     Print_OS((char *)s,TEXT_MODE_NORMAL,0);
11075 #else
11076     print(print_x,print_y,(const char *)s,color,false,false,false);
11077 #endif
11078   }
11079 
11080   // redraw_mode=1 clear area
Console_Disp(int redraw_mode,GIAC_CONTEXT)11081   int Console_Disp(int redraw_mode,GIAC_CONTEXT){
11082     unsigned int* pBitmap;
11083     int i, alpha_shift_status;
11084     DISPBOX ficon;
11085     int print_y = 0; //pixel y cursor
11086     int print_y_locate;
11087 
11088     // if (redraw_mode & 1) Bdisp_AllClr_VRAM();
11089 
11090     //GetFKeyIconPointer( 0x01BE, &ficon );
11091     //DisplayFKeyIcon( i, ficon);
11092 
11093     //Reading each "line" that will be printed
11094     for (i = 0; (i < LINE_DISP_MAX) && (i + Start_Line <= Last_Line); i++){
11095       console_line & curline=Line[i+Start_Line];
11096       if (i == Cursor.y){
11097 	// cursor line
11098 	//if ((redraw_mode & 1)==0)
11099 	  drawRectangle(0,i*vfontsize,LCD_WIDTH_PX,vfontsize,_WHITE);
11100 	if (curline.type == LINE_TYPE_INPUT || curline.type == LINE_TYPE_OUTPUT && curline.disp_len >= COL_DISP_MAX){
11101 	  locate(1, i + 1);
11102 	  if (curline.readonly){
11103 #ifdef CURSOR
11104 	    Cursor_SetFlashOff();
11105 #endif
11106 	    PrintRev(curline.str + curline.start_col);
11107 	  }
11108 	  else
11109 	    Print(curline.str+curline.start_col+(Cursor.x>COL_DISP_MAX-1?1:0));
11110 	}
11111 	else {
11112 	  locate(1, i + 1);
11113 	  print(print_x,print_y,(const char *)curline.str,TEXT_COLOR_BLACK,false,true/*fake*/,false);
11114 	  print_x=LCD_WIDTH_PX-print_x;
11115 	  if (curline.readonly){
11116 #ifdef CURSOR
11117 	    Cursor_SetFlashOff();
11118 #endif
11119 	    PrintRev(curline.str);
11120 	  }
11121 	  else
11122 	    Print(curline.str);
11123 	}
11124 
11125 	if (
11126 #if 1 //def CURSOR
11127 	    curline.disp_len - curline.start_col > COL_DISP_MAX-1
11128 #else
11129 	    print_x>LCD_WIDTH_PX-hfontsize
11130 #endif
11131 	    ){
11132 #ifdef CURSOR
11133 	  locate(COL_DISP_MAX, i + 1);
11134 #else
11135 	  print_y=i*vfontsize;
11136 	  print_x=LCD_WIDTH_PX+2-hfontsize;
11137 #endif
11138 	  if (curline.readonly){
11139 	    if(curline.disp_len - curline.start_col != COL_DISP_MAX) {
11140 #ifdef CURSOR
11141 	      Cursor_SetFlashOff();
11142 #endif
11143 	      PrintRev((char *)">",COLOR_MAGENTA);
11144 	    }
11145 	  }
11146 	  else if (Cursor.x < COL_DISP_MAX-1){
11147 	    Print((char *)">",COLOR_MAGENTA);
11148 	  }
11149 	}
11150 
11151 	if (curline.start_col > 0){
11152 	  locate(1, i + 1);
11153 	  if (curline.readonly){
11154 #ifdef CURSOR
11155 	    Cursor_SetFlashOff();
11156 #endif
11157 	    PrintRev((char *)"<",COLOR_MAGENTA);
11158 	  }
11159 	  else {
11160 	    Print((char *)"<",COLOR_MAGENTA);
11161 	  }
11162 	}
11163 
11164 	if (!curline.readonly){
11165 #ifdef CURSOR
11166 	  switch(GetSetupSetting( (unsigned int)0x14)) {
11167 	  case 0:
11168 	    alpha_shift_status = 0;
11169 	    break;
11170 	  case 1: //Shift enabled
11171 	    alpha_shift_status = 1;
11172 	    break;
11173 	  case 4: case 0x84:	//Alpha enabled
11174 	    alpha_shift_status = 2;
11175 	    break;
11176 	  case 8: case 0x88:
11177 	    alpha_shift_status = 4;
11178 	    break;
11179 	  default:
11180 	    alpha_shift_status = 0;
11181 	    break;
11182 	  }
11183 	  Cursor_SetPosition(Cursor.x, Cursor.y);
11184 	  Cursor_SetFlashOn(alpha_shift_status);
11185 	  //Cursor_SetFlashStyle(alpha_shift_status); //Potential 2.00 OS incompatibilty (cf Simon's doc)
11186 #else
11187 	  //locate(Cursor.x+1,Cursor.y+1);
11188 	  //DefineStatusMessage((giac::print_DOUBLE_(Cursor.y,6)+","+giac::print_DOUBLE_(print_y,6)).c_str(),1,0,0);
11189 	  //DisplayStatusArea();
11190 	  int fakestart=curline.start_col+(Cursor.x > COL_DISP_MAX-1?1:0);
11191 	  string fakes=string((const char *)curline.str).substr(fakestart,Cursor.x);
11192 	  int fakex=0,fakey=Cursor.y*vfontsize;
11193 	  print(fakex,fakey,fakes.c_str(),TEXT_COLOR_BLACK,false,true/* fake*/,false);
11194 	  drawRectangle(fakex,fakey,2,vfontsize,COLOR_BLACK);
11195 	  //drawRectangle(Cursor.x*hfontsize,24+Cursor.y*vfontsize,2,vfontsize,COLOR_BLACK);
11196 #endif
11197 	}
11198       } // end cursor line
11199       else {
11200 	if ((redraw_mode & 1)==0)
11201 	  continue;
11202 	drawRectangle(0,i*vfontsize,LCD_WIDTH_PX,vfontsize,_WHITE);
11203 	bool bigoutput = curline.type==LINE_TYPE_OUTPUT && curline.disp_len>=COL_DISP_MAX-3;
11204 	locate(bigoutput?3:1,i+1);
11205 	if (curline.type==LINE_TYPE_INPUT || bigoutput)
11206 	  Print(curline.str + curline.start_col);
11207 	else {
11208 #ifdef CURSOR
11209 	  locate(COL_DISP_MAX - Line[i + Start_Line].disp_len + 1, i + 1);
11210 #else
11211 	  print(print_x,print_y,(const char *)curline.str,TEXT_COLOR_BLACK,false,true/*fake*/,false);
11212 	  print_x=LCD_WIDTH_PX-print_x;
11213 #endif
11214 	  Print(curline.str);
11215 	}
11216 	if (curline.disp_len - curline.start_col > COL_DISP_MAX){
11217 #ifdef CURSOR
11218 	  locate(COL_DISP_MAX, i + 1);
11219 #else
11220 	  print_x=LCD_WIDTH_PX+2-hfontsize;
11221 #endif
11222 	  Print((char *)">",COLOR_BLUE);
11223 	}
11224 	if (curline.start_col > 0){
11225 #ifdef CURSOR
11226 	  locate(1, i + 1);
11227 #else
11228 	  print_x=0;
11229 #endif
11230 	  Print((char *)"<",COLOR_BLUE);
11231 	}
11232       } // end non cursor line
11233     } // end loop on all lines
11234     drawRectangle(0,i*vfontsize,LCD_WIDTH_PX,205-i*vfontsize,_WHITE);
11235 
11236     if ((redraw_mode & 1)==1){
11237       for (; (i < LINE_DISP_MAX) ; i++)
11238 	drawRectangle(0,i*vfontsize,LCD_WIDTH_PX,vfontsize,_WHITE);
11239       string menu("shift-1 ");
11240       menu += string(menu_f1);
11241       menu += "|2 ";
11242       menu += string(menu_f2);
11243       menu += "|3 ";
11244       menu += string(menu_f3);
11245       menu += xcas_python_eval==1?"|4 edt|5 2d|6 logo|7 lin|8 list|9plot|0 C":"|4 edt|5 2d|6 regr|7 matr|8 list|9 arit|0 C";
11246       drawRectangle(0,205,LCD_WIDTH_PX,17,_BLACK);
11247       PrintMiniMini(0,205,menu.c_str(),4);
11248     }
11249 
11250     // status, clock,
11251     console_disp_status(contextptr);
11252     return CONSOLE_SUCCEEDED;
11253   }
11254 
dConsoleRedraw()11255   void dConsoleRedraw(){
11256     Console_Disp(1,0);
11257   }
11258 
Console_GetLine(GIAC_CONTEXT)11259   char *Console_GetLine(GIAC_CONTEXT)
11260   {
11261     int return_val;
11262 
11263     do
11264       {
11265 	return_val = Console_GetKey(contextptr);
11266 	if (return_val==KEY_SHUTDOWN)
11267 	  return 0;
11268 	Console_Disp(1,contextptr);
11269 	if (return_val == KEY_CTRL_MENU) return 0;
11270 	if (return_val == CONSOLE_MEM_ERR) return NULL;
11271       } while (return_val != CONSOLE_NEW_LINE_SET);
11272 
11273     return Line[Current_Line - 1].str;
11274   }
11275 
11276   /*
11277     Simple accessor to the Edit_Line buffer.
11278   */
Console_GetEditLine()11279   char* Console_GetEditLine()
11280   {
11281     return Edit_Line;
11282   }
11283 
save_session(GIAC_CONTEXT)11284   void save_session(GIAC_CONTEXT){
11285     if (strcmp(session_filename,"session") && console_changed){
11286       string tmp(session_filename);
11287       tmp += (lang==1)?" a ete modifie!":" was modified!";
11288       if (confirm(tmp.c_str(),
11289 #ifdef NSPIRE_NEWLIB
11290 		  (lang==1)?"enter: sauve, esc: tant pis":"enter: save, esc: discard changes"
11291 #else
11292 		  (lang==1)?"OK: sauve, Back: tant pis":"OK: save, Back: discard changes"
11293 #endif
11294 		  )==KEY_CTRL_F1){
11295 	save(session_filename,contextptr);
11296 	console_changed=0;
11297       }
11298     }
11299     save("session",contextptr);
11300     // this is only called on exit, no need to reinstall the check_execution_abort timer.
11301     if (edptr && edptr->changed && edptr->filename!="session.py"){
11302       if (!check_leave(edptr)){
11303 	save_script("lastprg.py",merge_area(edptr->elements));
11304       }
11305     }
11306   }
11307 
11308 #ifdef NSPIRE_NEWLIB
nspire_fr()11309   bool nspire_fr(){
11310     char16_t input_w[] = u"getLangInfo()";
11311     void *math_expr = nullptr;
11312     int str_offset = 0;
11313 
11314     int error = TI_MS_evaluateExpr_ACBER(NULL, NULL, (const uint16_t*)input_w, &math_expr, &str_offset);
11315     if (error)
11316       return false;
11317 
11318     char16_t *output_w;
11319     error = TI_MS_MathExprToStr(math_expr, NULL, (uint16_t**)&output_w);
11320     syscall<e_free, void>(math_expr); // Should be TI_MS_DeleteMathExpr
11321 
11322     if (error)
11323       return false;
11324     int l=0;
11325     for (l=0;l<64;++l){
11326       if (output_w[l]==0)
11327 	break;
11328     }
11329     bool b=l==4 && output_w[1]=='f' && output_w[2]=='r';
11330     // Do something with output_w, it's u"42." here
11331 
11332     syscall<e_free, void>(output_w);
11333     return b;
11334   }
11335 #endif
11336 
11337   tableur * sheetptr=0;
console_main(GIAC_CONTEXT)11338   int console_main(GIAC_CONTEXT){
11339 #if defined NUMWORKS && defined MICROPY_LIB
11340     mp_stack_ctrl_init();
11341     char * heap=micropy_init();
11342     if (!heap)
11343       return 1;
11344 #endif
11345     sheetptr=0;
11346     shutdown=do_shutdown;
11347 #ifdef NSPIRE_NEWLIB
11348     // try to detect emulator or real calc
11349     unsigned NSPIRE_SPEED=0x900B0000;
11350     unsigned speed=*(unsigned *)NSPIRE_SPEED;
11351     nspireemu= (speed==1445890);
11352     mkdir("Xcas",0755);
11353     //mkdir("/Xcas",0755);
11354     //mkdir("A:/Xcas",0755);
11355     //mkdir("A:\\Xcas",0755);
11356     int err=chdir("Xcas");
11357     if (err)
11358       err=chdir("ndless");
11359     bool b=nspire_fr();
11360     lang=b?1:0;
11361 #endif
11362     // SetQuitHandler(save_session); // automatically save session when exiting
11363     if (!turtleptr){
11364       turtle();
11365       _efface_logo(vecteur(0),contextptr);
11366     }
11367     int key;
11368     Console_Init(contextptr);
11369     Bdisp_AllClr_VRAM();
11370     rand_seed(millis(),contextptr);
11371     restore_session("session",contextptr);
11372     giac::angle_radian(os_get_angle_unit()==0,contextptr);
11373     //GetKey(&key);
11374     Console_Disp(1,contextptr);
11375     // GetKey(&key);
11376     char *expr=0;
11377 #ifndef NO_STDEXCEPT
11378     try {
11379 #endif
11380     while(1){
11381       if ((expr=Console_GetLine(contextptr))==NULL){
11382 	save_session(contextptr);
11383 #ifdef NUMWORKS
11384 	return 0;
11385 #endif
11386 #ifdef MICROPY_LIB
11387 	mp_deinit(); free(heap);
11388 #endif
11389 	Console_Free();
11390 	release_globals();
11391 	if (sheetptr){
11392 	  // sheetptr->m.clear();
11393 	  delete sheetptr;
11394 	  sheetptr=0;
11395 	}
11396 	return 0;
11397       }
11398       if (strcmp((const char *)expr,"restart")==0){
11399 	if (confirm((lang==1)?"Effacer variables?":"Clear variables?",
11400 #ifdef NSPIRE_NEWLIB
11401 		    (lang==1)?"enter: annul,  esc: confirmer":"enter: cancel,  esc: confirm"
11402 #else
11403 		    (lang==1)?"OK: annul,  Back: confirmer":"OK: cancel,  Back: confirm"
11404 #endif
11405 		    )!=KEY_CTRL_F6){
11406 	  Console_Output(" cancelled");
11407 	  Console_NewLine(LINE_TYPE_OUTPUT,1);
11408 	  //GetKey(&key);
11409 	  Console_Disp(1,contextptr);
11410 	  continue;
11411 	}
11412       }
11413       // should save in another file
11414       if (strcmp((const char *)expr,"=>")==0 || strcmp((const char *)expr,"=>\n")==0){
11415 	save_session(contextptr);
11416 	Console_Output("Session saved");
11417       }
11418       else
11419 	run(expr,7,contextptr);
11420       //print_mem_info();
11421       Console_NewLine(LINE_TYPE_OUTPUT,1);
11422       //GetKey(&key);
11423       Console_Disp(1,contextptr);
11424     }
11425 #ifndef NO_STDEXCEPT
11426     } catch(autoshutdown & e) {
11427     }
11428 #endif
11429 #ifdef NUMWORKS
11430     return 0;
11431 #endif
11432     Console_Free();
11433     release_globals();
11434 #ifdef MICROPY_LIB
11435     mp_deinit(); free(heap);
11436 #endif
11437     if (sheetptr){
11438       // sheetptr->m.clear();
11439       delete sheetptr;
11440       sheetptr=0;
11441     }
11442     return 0;
11443   }
11444 
11445 
11446 #endif // TEXTAREA
11447 
rgb24to16(int c)11448   int rgb24to16(int c){
11449     int r=(c>>16)&0xff,g=(c>>8)&0xff,b=c&0xff;
11450     return (((r*32)/256)<<11) | (((g*64)/256)<<5) | (b*32/256);
11451   }
11452 
11453   // table periodique, code adapte de https://github.com/M4xi1m3/nw-atom
11454   // avec l'aimable autorisation de diffusion sous licence GPL de Maxime Friess
11455   // https://tiplanet.org/forum/viewtopic.php?f=97&t=23094&p=247471#p247471
11456 enum AtomType {
11457   ALKALI_METAL,
11458   ALKALI_EARTH_METAL,
11459   LANTHANIDE,
11460   ACTINIDE,
11461   TRANSITION_METAL,
11462   POST_TRANSITION_METAL,
11463   METALLOID,
11464   HALOGEN,
11465   REACTIVE_NONMETAL,
11466   NOBLE_GAS,
11467   UNKNOWN
11468 };
11469 
11470 struct AtomDef {
11471   uint8_t num;
11472   uint8_t x;
11473   uint8_t y;
11474   AtomType type;
11475   const char* name;
11476   const char* symbol;
11477   uint8_t neutrons;
11478   double mass;
11479   double electroneg;
11480 };
11481 
11482 const AtomDef atomsdefs[] = {
11483   {  1,  0,  0, REACTIVE_NONMETAL       , "Hydrogen"     , "H"   ,   0, 1.00784     , 2.2   },
11484   {  2, 17,  0, NOBLE_GAS               , "Helium"       , "He"  ,   2, 4.002602    , -1    },
11485 
11486 
11487   {  3,  0,  1, ALKALI_METAL            , "Lithium"      , "Li"  ,   4, 6.938       , 0.98  },
11488   {  4,  1,  1, ALKALI_EARTH_METAL      , "Beryllium"    , "Be"  ,   5, 9.012182    , 1.57  },
11489   {  5, 12,  1, METALLOID               , "Boron"        , "B"   ,   6, 10.806      , 2.04  },
11490   {  6, 13,  1, REACTIVE_NONMETAL       , "Carbon"       , "C"   ,   6, 12.0096     , 2.55  },
11491   {  7, 14,  1, REACTIVE_NONMETAL       , "Nitrogen"     , "N"   ,   7, 14.00643    , 3.04  },
11492   {  8, 15,  1, REACTIVE_NONMETAL       , "Oxygen"       , "O"   ,   8, 15.99903    , 3.44  },
11493   {  9, 16,  1, HALOGEN                 , "Fluorine"     , "F"   ,  10, 18.9984032  , 3.98  },
11494   { 10, 17,  1, NOBLE_GAS               , "Neon"         , "Ne"  ,  10, 20.1797     , -1    },
11495 
11496 
11497   { 11,  0,  2, ALKALI_METAL            , "Sodium"       , "Na"  ,  12, 22.9897693  , 0.93  },
11498   { 12,  1,  2, ALKALI_EARTH_METAL      , "Magnesium"    , "Mg"  ,  12, 24.3050     , 1.31  },
11499   { 13, 12,  2, POST_TRANSITION_METAL   , "Aluminium"    , "Al"  ,  14, 26.9815386  , 1.61  },
11500   { 14, 13,  2, METALLOID               , "Silicon"      , "Si"  ,  14, 28.084      , 1.9   },
11501   { 15, 14,  2, REACTIVE_NONMETAL       , "Phosphorus"   , "P"   ,  16, 30.973762   , 2.19  },
11502   { 16, 15,  2, REACTIVE_NONMETAL       , "Sulfur"       , "S"   ,  16, 32.059      , 2.58  },
11503   { 17, 16,  2, HALOGEN                 , "Chlorine"     , "Cl"  ,  18, 35.446      , 3.16  },
11504   { 18, 17,  2, NOBLE_GAS               , "Argon"        , "Ar"  ,  22, 39.948      , -1    },
11505 
11506 
11507   { 19,  0,  3, ALKALI_METAL            , "Potassium"    , "K"   ,  20, 39.0983     , 0.82  },
11508   { 20,  1,  3, ALKALI_EARTH_METAL      , "Calcium"      , "Ca"  ,  20, 40.078      , 1     },
11509   { 21,  2,  3, TRANSITION_METAL        , "Scandium"     , "Sc"  ,  24, 44.955912   , 1.36  },
11510   { 22,  3,  3, TRANSITION_METAL        , "Titanium"     , "Ti"  ,  26, 47.867      , 1.54  },
11511   { 23,  4,  3, TRANSITION_METAL        , "Vanadium"     , "V"   ,  28, 50.9415     , 1.63  },
11512   { 24,  5,  3, TRANSITION_METAL        , "Chromium"     , "Cr"  ,  28, 51.9961     , 1.66  },
11513   { 25,  6,  3, TRANSITION_METAL        , "Manganese"    , "Mn"  ,  30, 54.938045   , 1.55  },
11514   { 26,  7,  3, TRANSITION_METAL        , "Iron"         , "Fe"  ,  30, 55.845      , 1.83  },
11515   { 27,  8,  3, TRANSITION_METAL        , "Cobalt"       , "Co"  ,  32, 58.933195   , 1.88  },
11516   { 28,  9,  3, TRANSITION_METAL        , "Nickel"       , "Ni"  ,  30, 58.6934     , 1.91  },
11517   { 29, 10,  3, TRANSITION_METAL        , "Copper"       , "Cu"  ,  34, 63.546      , 1.9   },
11518   { 30, 11,  3, POST_TRANSITION_METAL   , "Zinc"         , "Zn"  ,  34, 65.38       , 1.65  },
11519   { 31, 12,  3, POST_TRANSITION_METAL   , "Gallium"      , "Ga"  ,  38, 69.723      , 1.81  },
11520   { 32, 13,  3, METALLOID               , "Germanium"    , "Ge"  ,  42, 72.63       , 2.01  },
11521   { 33, 14,  3, METALLOID               , "Arsenic"      , "As"  ,  42, 74.92160    , 2.18  },
11522   { 34, 15,  3, REACTIVE_NONMETAL       , "Selenium"     , "Se"  ,  46, 78.96       , 2.55  },
11523   { 35, 16,  3, HALOGEN                 , "Bromine"      , "Br"  ,  44, 79.904      , 2.96  },
11524   { 36, 17,  3, NOBLE_GAS               , "Krypton"      , "Kr"  ,  48, 83.798      , -1    },
11525 
11526   { 37,  0,  4, ALKALI_METAL            , "Rubidium"     , "Rb"  ,  48, 85.4678     , 0.82  },
11527   { 38,  1,  4, ALKALI_EARTH_METAL      , "Strontium"    , "Sr"  ,  50, 87.62       , 0.95  },
11528   { 39,  2,  4, TRANSITION_METAL        , "Yttrium"      , "Y"   ,  50, 88.90585    , 1.22  },
11529   { 40,  3,  4, TRANSITION_METAL        , "Zirconium"    , "Zr"  ,  50, 91.224      , 1.33  },
11530   { 41,  4,  4, TRANSITION_METAL        , "Niobium"      , "Nb"  ,  52, 92.90638    , 1.6   },
11531   { 42,  5,  4, TRANSITION_METAL        , "Molybdenum"   , "Mo"  ,  56, 95.96       , 2.16  },
11532   { 43,  6,  4, TRANSITION_METAL        , "Technetium"   , "Tc"  ,  55, 98          , 2.10  },
11533   { 44,  7,  4, TRANSITION_METAL        , "Ruthemium"    , "Ru"  ,  58, 101.07      , 2.2   },
11534   { 45,  8,  4, TRANSITION_METAL        , "Rhodium"      , "Rh"  ,  58, 102.90550   , 2.28  },
11535   { 46,  9,  4, TRANSITION_METAL        , "Palladium"    , "Pd"  ,  60, 106.42      , 2.20  },
11536   { 47, 10,  4, TRANSITION_METAL        , "Silver"       , "Ag"  ,  60, 107.8682    , 1.93  },
11537   { 48, 11,  4, POST_TRANSITION_METAL   , "Cadmium"      , "Cd"  ,  66, 112.411     , 1.69  },
11538   { 49, 12,  4, POST_TRANSITION_METAL   , "Indium"       , "In"  ,  66, 114.818     , 1.78  },
11539   { 50, 13,  4, POST_TRANSITION_METAL   , "Tin"          , "Sn"  ,  70, 118.710     , 1.96  },
11540   { 51, 14,  4, METALLOID               , "Antimony"     , "Sb"  ,  70, 121.760     , 2.05  },
11541   { 52, 15,  4, METALLOID               , "Tellurium"    , "Te"  ,  78, 127.60      , 2.1   },
11542   { 53, 16,  4, HALOGEN                 , "Indine"       , "I"   ,  74, 126.90447   , 2.66  },
11543   { 54, 17,  4, NOBLE_GAS               , "Xenon"        , "Xe"  ,  78, 131.293     , 2.60  },
11544 
11545 
11546   { 55,  0,  5, ALKALI_METAL            , "Caesium"      , "Cs"  ,  78, 132.905452  , 0.79  },
11547   { 56,  1,  5, ALKALI_EARTH_METAL      , "Barium"       , "Ba"  ,  82, 137.327     , 0.89  },
11548 
11549   { 57,  3,  7, LANTHANIDE              , "Lanthanum"    , "La"  ,  82, 138.90547   , 1.10  },
11550   { 58,  4,  7, LANTHANIDE              , "Cerium"       , "Ce"  ,  82, 140.116     , 1.12  },
11551   { 59,  5,  7, LANTHANIDE              , "Praseodymium" , "Pr"  ,  82, 140.90765   , 1.13  },
11552   { 60,  6,  7, LANTHANIDE              , "Neodymium"    , "Nd"  ,  82, 144.242     , 1.14  },
11553   { 61,  7,  7, LANTHANIDE              , "Promethium"   , "Pm"  ,  84, 145         , 1.13  },
11554   { 62,  8,  7, LANTHANIDE              , "Samarium"     , "Sm"  ,  90, 150.36      , 1.17  },
11555   { 63,  9,  7, LANTHANIDE              , "Europium"     , "Eu"  ,  90, 151.964     , 1.12  },
11556   { 64, 10,  7, LANTHANIDE              , "Gadolinium"   , "Gd"  ,  94, 157.25      , 1.20  },
11557   { 65, 11,  7, LANTHANIDE              , "Terbium"      , "Tb"  ,  94, 158.92535   , 1.12  },
11558   { 66, 12,  7, LANTHANIDE              , "Dyxprosium"   , "Dy"  ,  98, 162.500     , 1.22  },
11559   { 67, 13,  7, LANTHANIDE              , "Holmium"      , "Ho"  ,  98, 164.93032   , 1.23  },
11560   { 68, 14,  7, LANTHANIDE              , "Erbium"       , "Er"  ,  98, 167.259     , 1.24  },
11561   { 69, 15,  7, LANTHANIDE              , "Thulium"      , "Tm"  , 100, 168.93421   , 1.25  },
11562   { 70, 16,  7, LANTHANIDE              , "Ytterbium"    , "Yb"  , 104, 173.054     , 1.1   },
11563   { 71, 17,  7, LANTHANIDE              , "Lutetium"     , "Lu"  , 104, 174.9668    , 1.0   },
11564 
11565   { 72,  3,  5, TRANSITION_METAL        , "Hafnium"      , "Hf"  , 108, 178.49      , 1.3   },
11566   { 73,  4,  5, TRANSITION_METAL        , "Tantalum"     , "Ta"  , 108, 180.94788   , 1.5   },
11567   { 74,  5,  5, TRANSITION_METAL        , "Tungsten"     , "W"   , 110, 183.84      , 1.7   },
11568   { 75,  6,  5, TRANSITION_METAL        , "Rhenium"      , "Re"  , 112, 186.207     , 1.9   },
11569   { 76,  7,  5, TRANSITION_METAL        , "Osmium"       , "Os"  , 116, 190.23      , 2.2   },
11570   { 77,  8,  5, TRANSITION_METAL        , "Iridium"      , "Ir"  , 116, 192.217     , 2.2   },
11571   { 78,  9,  5, TRANSITION_METAL        , "Platinum"     , "Pt"  , 117, 195.084     , 2.2   },
11572   { 79, 10,  5, TRANSITION_METAL        , "Gold"         , "Au"  , 118, 196.966569  , 2.4   },
11573   { 80, 11,  5, POST_TRANSITION_METAL   , "Mercury"      , "Hg"  , 122, 200.59      , 1.9   },
11574   { 81, 12,  5, POST_TRANSITION_METAL   , "Thalium"      , "Tl"  , 124, 204.382     , 1.8   },
11575   { 82, 13,  5, POST_TRANSITION_METAL   , "Lead"         , "Pb"  , 126, 207.2       , 1.8   },
11576   { 83, 14,  5, POST_TRANSITION_METAL   , "Bismuth"      , "Bi"  , 126, 208.98040   , 1.9   },
11577   { 84, 15,  5, POST_TRANSITION_METAL   , "Polonium"     , "Po"  , 126, 209         , 2.0   },
11578   { 85, 16,  5, HALOGEN                 , "Astatine"     , "At"  , 125, 210         , 2.2   },
11579   { 86, 17,  5, NOBLE_GAS               , "Radon"        , "Rn"  , 136, 222         , 2.2   },
11580 
11581 
11582   { 87,  0,  6, ALKALI_METAL            , "Francium"     , "Fr"  , 136, 223         , 0.7   },
11583   { 88,  1,  6, ALKALI_EARTH_METAL      , "Radium"       , "Ra"  , 138, 226         , 0.9   },
11584 
11585   { 89,  3,  8, ACTINIDE                , "Actinium"     , "Ac"  , 138, 227         , 1.1   },
11586   { 90,  4,  8, ACTINIDE                , "Thorium"      , "Th"  , 142, 232.03806   , 1.3   },
11587   { 91,  5,  8, ACTINIDE                , "Protactinium" , "Pa"  , 140, 231.03588   , 1.5   },
11588   { 92,  6,  8, ACTINIDE                , "Uranium"      , "U"   , 146, 238.02891   , 1.38   },
11589   { 93,  7,  8, ACTINIDE                , "Neptunium"    , "Np"  , 144, 237         , 1.36   },
11590   { 94,  8,  8, ACTINIDE                , "Plutonium"    , "Pu"  , 150, 244         , 1.28   },
11591   { 95,  9,  8, ACTINIDE                , "Americium"    , "Am"  , 148, 243         , 1.13  },
11592   { 96, 10,  8, ACTINIDE                , "Curium"       , "Cm"  , 151, 247         , 1.28  },
11593   { 97, 11,  8, ACTINIDE                , "Berkellum"    , "Bk"  , 150, 247         , 1.3   },
11594   { 98, 12,  8, ACTINIDE                , "Californium"  , "Cf"  , 153, 251         , 1.3   },
11595   { 99, 13,  8, ACTINIDE                , "Einsteinium"  , "Es"  , 153, 252         , 1.3   },
11596   {100, 14,  8, ACTINIDE                , "Fermium"      , "Fm"  , 157, 257         , 1.3   },
11597   {101, 15,  8, ACTINIDE                , "Mendelevium"  , "Md"  , 157, 258         , 1.3   },
11598   {102, 16,  8, ACTINIDE                , "Nobelium"     , "No"  , 157, 259         , 1.3   },
11599   {103, 17,  8, ACTINIDE                , "Lawrencium"   , "Lr"  , 163, 262         , 1.3   },
11600 
11601   {104,  3,  6, TRANSITION_METAL        , "Rutherfordium", "Rf"  , 163, 261         , -1    },
11602   {105,  4,  6, TRANSITION_METAL        , "Dubnium"      , "Db"  , 163, 262         , -1    },
11603   {106,  5,  6, TRANSITION_METAL        , "Seaborgium"   , "Sg"  , 163, 263         , -1    },
11604   {107,  6,  6, TRANSITION_METAL        , "Bohrium"      , "Bh"  , 163, 264         , -1    },
11605   {108,  7,  6, TRANSITION_METAL        , "Hassium"      , "Hs"  , 169, 265         , -1    },
11606   {109,  8,  6, UNKNOWN                 , "Meitnerium"   , "Mt"  , 169, 268         , -1    },
11607   {110,  9,  6, UNKNOWN                 , "Damstadtium"  , "Ds"  , 171, 281         , -1    },
11608   {111, 10,  6, UNKNOWN                 , "Roentgenium"  , "Rg"  , 171, 273         , -1    },
11609   {112, 11,  6, POST_TRANSITION_METAL   , "Coppernicium" , "Cn"  , 173, 277         , -1    },
11610   {113, 12,  6, UNKNOWN                 , "Nihonium"     , "Nh"  , 173, 283         , -1    },
11611   {114, 13,  6, UNKNOWN                 , "Flerovium"    , "Fl"  , 175, 285         , -1    },
11612   {115, 14,  6, UNKNOWN                 , "Moscovium"    , "Mv"  , 174, 287         , -1    },
11613   {116, 15,  6, UNKNOWN                 , "Livermorium"  , "Lv"  , 177, 289         , -1    },
11614   {117, 16,  6, UNKNOWN                 , "Tennessine"   , "Ts"  , 177, 294         , -1    },
11615   {118, 17,  6, NOBLE_GAS               , "Oganesson"    , "Og"  , 176, 293         , -1    },
11616 
11617 };
11618 
drawAtom(uint8_t id)11619 void drawAtom(uint8_t id) {
11620   int fill = rgb24to16(0xeeeeee);
11621 
11622   switch(atomsdefs[id].type) {
11623     case ALKALI_METAL:
11624       fill = rgb24to16(0xffaa00);
11625       break;
11626     case ALKALI_EARTH_METAL:
11627       fill = rgb24to16(0xf6f200);
11628       break;
11629     case LANTHANIDE:
11630       fill = rgb24to16(0xffaa8b);
11631       break;
11632     case ACTINIDE:
11633       fill = rgb24to16(0xdeaacd);
11634       break;
11635     case TRANSITION_METAL:
11636       fill = rgb24to16(0xde999c);
11637       break;
11638     case POST_TRANSITION_METAL:
11639       fill = rgb24to16(0x9cbaac);
11640       break;
11641     case METALLOID:
11642       fill = rgb24to16(0x52ce8b);
11643       break;
11644     case REACTIVE_NONMETAL:
11645       fill = rgb24to16(0x00ee00);
11646       break;
11647     case NOBLE_GAS:
11648       fill = rgb24to16(0x8baaff);
11649       break;
11650     case HALOGEN:
11651       fill = rgb24to16(0x00debd);
11652       break;
11653     default:
11654       break;
11655   }
11656 
11657   if (atomsdefs[id].y >= 7) {
11658     drawRectangle(6 + atomsdefs[id].x * 17, 15 + atomsdefs[id].y * 17, 18, 18, fill);
11659     stroke_rectangle(6 + atomsdefs[id].x * 17, 15 + atomsdefs[id].y * 17, 18, 18, rgb24to16(0x525552));
11660     os_draw_string_small(8 + atomsdefs[id].x * 17, 17 + atomsdefs[id].y * 17, _BLACK, fill, atomsdefs[id].symbol);
11661   } else {
11662     drawRectangle(6 + atomsdefs[id].x * 17, 6 + atomsdefs[id].y * 17, 18, 18, fill);
11663     stroke_rectangle(6 + atomsdefs[id].x * 17, 6 + atomsdefs[id].y * 17, 18, 18, rgb24to16(0x525552));
11664     os_draw_string_small(8 + atomsdefs[id].x * 17, 8 + atomsdefs[id].y * 17, _BLACK, fill, atomsdefs[id].symbol);
11665   }
11666 }
11667 
periodic_table(const char * & name,const char * & symbol,char * protons,char * nucleons,char * mass,char * electroneg)11668   int periodic_table(const char * & name,const char * & symbol,char * protons,char * nucleons,char * mass,char * electroneg){
11669     bool partial_draw=false,redraw=true;
11670     int cursor_pos=0;
11671     const int ATOM_NUMS=sizeof(atomsdefs)/sizeof(AtomDef);
11672     for (;;){
11673       if (redraw){
11674 	if (partial_draw) {
11675 	  partial_draw = false;
11676 	  drawRectangle(50, 0, 169, 57, _WHITE);
11677 	  drawRectangle(0, 185, LCD_WIDTH_PX, 15, _WHITE);
11678 	} else {
11679 	  drawRectangle(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,_WHITE);
11680 	}
11681 #ifdef NSPIRE_NEWLIB
11682 	os_draw_string_small_(0,200,gettext("enter: tout, P:protons, N:nucleons, M:mass, E:khi"));
11683 #else
11684 	os_draw_string_small_(0,200,gettext("OK: tout, P:protons, N:nucleons, M:mass, E:khi"));
11685 #endif
11686 	for(int i = 0; i < ATOM_NUMS; i++) {
11687 	  drawAtom(i);
11688 	}
11689 	if (atomsdefs[cursor_pos].y >= 7) {
11690 	  stroke_rectangle(6 + atomsdefs[cursor_pos].x * 17, 15 + atomsdefs[cursor_pos].y * 17, 18, 18, 0x000000);
11691 	  stroke_rectangle(7 + atomsdefs[cursor_pos].x * 17, 16 + atomsdefs[cursor_pos].y * 17, 16, 16, 0x000000);
11692 	} else {
11693 	  stroke_rectangle(6 + atomsdefs[cursor_pos].x * 17, 6 + atomsdefs[cursor_pos].y * 17, 18, 18, 0x000000);
11694 	  stroke_rectangle(7 + atomsdefs[cursor_pos].x * 17, 7 + atomsdefs[cursor_pos].y * 17, 16, 16, 0x000000);
11695 	}
11696 
11697 	drawRectangle(48,  99, 2, 61,rgb24to16(0x525552));
11698 	drawRectangle(48, 141, 9,  2, rgb24to16(0x525552));
11699 	drawRectangle(48, 158, 9,  2, rgb24to16(0x525552));
11700 
11701 	int prot=atomsdefs[cursor_pos].num;
11702 	sprint_int(protons,prot);
11703 	int nuc=atomsdefs[cursor_pos].neutrons+atomsdefs[cursor_pos].num;
11704 	sprint_int(nucleons,nuc);
11705 
11706 	symbol=atomsdefs[cursor_pos].symbol;
11707 	os_draw_string_(73,23,symbol);
11708 	name=atomsdefs[cursor_pos].name;
11709 	os_draw_string_small_(110,27,gettext(name));
11710 	os_draw_string_small_(50,18,nucleons);
11711 	os_draw_string_small_(50,31,protons);
11712 	strcpy(mass,"M:");
11713 	strcpy(electroneg,"khi:");
11714 	sprint_double(mass+2,atomsdefs[cursor_pos].mass);
11715 	os_draw_string_small_(0,186,mass);
11716 	sprint_double(electroneg+4,atomsdefs[cursor_pos].electroneg);
11717 	os_draw_string_small_(160,186,electroneg);
11718       }
11719       redraw=false;
11720       int key;
11721       GetKey(&key);
11722       if (key==KEY_SHUTDOWN)
11723 	return key;
11724       if (key==KEY_PRGM_ACON)
11725 	redraw=true;
11726       if (key==KEY_CTRL_EXIT)
11727 	return 0;
11728       if (key==KEY_CTRL_EXE || key==KEY_CTRL_OK)
11729 	return 1|4|8|16|32;
11730       if (key=='s' || key==KEY_CHAR_5)
11731 	return 2;
11732       if (key=='p' || key==KEY_CHAR_LPAR)
11733 	return 4;
11734       if (key=='n' || key==KEY_CHAR_8)
11735 	return 8;
11736       if (key=='m' || key==KEY_CHAR_7)
11737 	return 16;
11738       if (key=='e' || key==KEY_CHAR_COMMA)
11739 	return 32;
11740       if (key==KEY_CTRL_LEFT){
11741 	if (cursor_pos>0)
11742 	  --cursor_pos;
11743 	redraw=partial_draw=true;
11744       }
11745       if (key==KEY_CTRL_RIGHT){
11746 	if (cursor_pos< ATOM_NUMS-1)
11747 	  ++cursor_pos;
11748 	redraw=partial_draw=true;
11749       }
11750       if (key==KEY_CTRL_UP){
11751 	uint8_t curr_x = atomsdefs[cursor_pos].x;
11752 	uint8_t curr_y = atomsdefs[cursor_pos].y;
11753 	bool updated = false;
11754 
11755 	if (curr_y > 0 && curr_y <= 9) {
11756 	  for(uint8_t i = 0; i < ATOM_NUMS; i++) {
11757 	    if (atomsdefs[i].x == curr_x && atomsdefs[i].y == curr_y - 1) {
11758 	      cursor_pos = i;
11759 	      redraw=partial_draw = true;
11760 	    }
11761 	  }
11762 	}
11763 
11764       }
11765       if (key==KEY_CTRL_DOWN){
11766 	uint8_t curr_x = atomsdefs[cursor_pos].x;
11767 	uint8_t curr_y = atomsdefs[cursor_pos].y;
11768 	bool updated = false;
11769 
11770 	if (curr_y >= 0 && curr_y < 9) {
11771 	  for (uint8_t i = 0; i < ATOM_NUMS; i++) {
11772 	    if (atomsdefs[i].x == curr_x && atomsdefs[i].y == curr_y + 1) {
11773 	      cursor_pos = i;
11774 	      redraw=partial_draw = true;
11775 	      break;
11776 	    }
11777 	  }
11778 	}
11779       }
11780     } // end endless for
11781   } // end periodic_table
11782 
11783 #ifndef NO_NAMESPACE_XCAS
11784 } // namespace xcas
11785 #endif // ndef NO_NAMESPACE_XCAS
11786 
console_output(const char * s,int l)11787 void console_output(const char * s,int l){
11788   char buf[l+1];
11789   strncpy(buf,s,l);
11790   buf[l]=0;
11791   xcas::dConsolePut(buf);
11792 }
11793 
console_input(const char * msg1,const char * msg2,bool numeric,int ypos)11794 const char * console_input(const char * msg1,const char * msg2,bool numeric,int ypos){
11795   static string str;
11796   if (!giac::inputline(msg1,msg2,str,numeric,ypos,context0))
11797     return 0;
11798   return str.c_str();
11799 }
11800 
c_draw_rectangle(int x,int y,int w,int h,int c)11801 void c_draw_rectangle(int x,int y,int w,int h,int c){
11802   giac::freeze=true;
11803   xcas::draw_line(x,y,x+w,y,c);
11804   xcas::draw_line(x+w,y,x+w,y+h,c);
11805   xcas::draw_line(x,y+h,x+w,y+h,c);
11806   xcas::draw_line(x,y,x,y+h,c);
11807 }
c_draw_line(int x0,int y0,int x1,int y1,int c)11808 void c_draw_line(int x0,int y0,int x1,int y1,int c){
11809   giac::freeze=true;
11810   xcas::draw_line(x0,y0,x1,y1,c);
11811 }
c_draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4)11812 void c_draw_circle(int xc,int yc,int r,int color,bool q1,bool q2,bool q3,bool q4){
11813   giac::freeze=true;
11814   xcas::draw_circle(xc,yc,r,color,q1,q2,q3,q4);
11815 }
c_draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right)11816 void c_draw_filled_circle(int xc,int yc,int r,int color,bool left,bool right){
11817   giac::freeze=true;
11818   xcas::draw_filled_circle(xc,yc,r,color,left,right);
11819 }
c_convert(int * x,int * y,vector<vector<int>> & v)11820 void c_convert(int *x,int*y,vector< vector<int> > & v){
11821   for (int i=0;i<v.size();++i,++x,++y){
11822     v[i].push_back(*x);
11823     v[i].push_back(*y);
11824   }
11825 }
c_draw_polygon(int * x,int * y,int n,int color)11826 void c_draw_polygon(int * x,int *y ,int n,int color){
11827   giac::freeze=true;
11828   vector< vector<int> > v(n);
11829   c_convert(x,y,v);
11830   xcas::draw_polygon(v,color);
11831 }
c_draw_filled_polygon(int * x,int * y,int n,int xmin,int xmax,int ymin,int ymax,int color)11832 void c_draw_filled_polygon(int * x,int *y, int n,int xmin,int xmax,int ymin,int ymax,int color){
11833   giac::freeze=true;
11834   vector< vector<int> > v(n);
11835   c_convert(x,y,v);
11836   xcas::draw_filled_polygon(v,xmin,xmax,ymin,ymax,color);
11837 }
c_draw_arc(int xc,int yc,int rx,int ry,int color,double theta1,double theta2)11838 void c_draw_arc(int xc,int yc,int rx,int ry,int color,double theta1, double theta2){
11839   giac::freeze=true;
11840   xcas::draw_arc(xc,yc,rx,ry,color,theta1,theta2);
11841 }
c_draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment)11842 void c_draw_filled_arc(int x,int y,int rx,int ry,int theta1_deg,int theta2_deg,int color,int xmin,int xmax,int ymin,int ymax,bool segment){
11843   giac::freeze=true;
11844   xcas::draw_filled_arc(x,y,rx,ry,theta1_deg,theta2_deg,color,xmin,xmax,ymin,ymax,segment);
11845 }
c_set_pixel(int x,int y,int c)11846 void c_set_pixel(int x,int y,int c){
11847   giac::freeze=true;
11848   os_set_pixel(x,y,c);
11849 }
c_fill_rect(int x,int y,int w,int h,int c)11850 void c_fill_rect(int x,int y,int w,int h,int c){
11851   giac::freeze=true;
11852   os_fill_rect(x,y,w,h,c);
11853 }
c_draw_string(int x,int y,int c,int bg,const char * s,bool fake)11854 int c_draw_string(int x,int y,int c,int bg,const char * s,bool fake){
11855   giac::freeze=true;
11856   return os_draw_string(x,y,c,bg,s,fake);
11857 }
c_draw_string_small(int x,int y,int c,int bg,const char * s,bool fake)11858 int c_draw_string_small(int x,int y,int c,int bg,const char * s,bool fake){
11859   giac::freeze=true;
11860   return os_draw_string_small(x,y,c,bg,s,fake);
11861 }
c_draw_string_medium(int x,int y,int c,int bg,const char * s,bool fake)11862 int c_draw_string_medium(int x,int y,int c,int bg,const char * s,bool fake){
11863   giac::freeze=true;
11864   return os_draw_string_medium(x,y,c,bg,s,fake);
11865 }
11866 
select_item(const char ** ptr,const char * title,bool askfor1)11867 int select_item(const char ** ptr,const char * title,bool askfor1){
11868   int nitems=0;
11869   for (const char ** p=ptr;*p;++p)
11870     ++nitems;
11871   if (nitems==0 || nitems>=256)
11872     return -1;
11873   if (!askfor1 && nitems==1)
11874     return 0;
11875   MenuItem smallmenuitems[nitems];
11876   for (int i=0;i<nitems;++i){
11877     smallmenuitems[i].text=(char *) ptr[i];
11878   }
11879   Menu smallmenu;
11880   smallmenu.numitems=nitems;
11881   smallmenu.items=smallmenuitems;
11882   smallmenu.height=12;
11883   smallmenu.scrollbar=1;
11884   smallmenu.scrollout=1;
11885   smallmenu.title = (char*) title;
11886   //MsgBoxPush(5);
11887   int sres = doMenu(&smallmenu);
11888   //MsgBoxPop();
11889   if (sres!=MENU_RETURN_SELECTION && sres!=KEY_CTRL_EXE)
11890     return -1;
11891   return smallmenu.selection-1;
11892 }
11893 
select_interpreter()11894 int select_interpreter(){
11895   const char * choix[]={"Xcas interpreter","Xcas compat Python ^=**","Xcas compat Python ^=xor","MicroPython interpreter",0};
11896   return select_item(choix,"Syntax",false);
11897 }
11898 
double2gen(double d)11899 ulonglong double2gen(double d){
11900   giac::gen g(d);
11901   return *(ulonglong *) &g;
11902 }
11903 
int2gen(int d)11904 ulonglong int2gen(int d){
11905   giac::gen g(d);
11906   return *(ulonglong *) &g;
11907 }
11908 
turtle_freeze()11909 void turtle_freeze(){
11910   freezeturtle=true;
11911 }
11912 
doubleptr2matrice(double * x,int n,int m,giac::matrice & M)11913 void doubleptr2matrice(double * x,int n,int m,giac::matrice & M){
11914   M.resize(n);
11915   for (int i=0;i<n;++i){
11916     M[i]=giac::vecteur(m);
11917     giac::vecteur & w=*M[i]._VECTptr;
11918     for (int j=0;j<m;++j){
11919       w[j]=*x;
11920       ++x;
11921     }
11922   }
11923 }
11924 
11925 // x must have enough space!
matrice2doubleptr(const giac::matrice & M,double * x)11926 bool matrice2doubleptr(const giac::matrice &M,double *x){
11927   int n=M.size();
11928   if (n==0 || M.front().type!=giac::_VECT)
11929     return false;
11930   int m=M.front()._VECTptr->size();
11931   for (int i=0;i<n;++i){
11932     if (M[i].type!=giac::_VECT || M[i]._VECTptr->size()!=m)
11933       return false;
11934     giac::vecteur & w=*M[i]._VECTptr;
11935     for (int j=0;j<m;++j){
11936       giac::gen g =giac::evalf_double(w[j],1,giac::context0);
11937       if (g.type!=giac::_DOUBLE_)
11938 	return false;
11939       *x=g._DOUBLE_val;
11940       ++x;
11941     }
11942   }
11943   return true;
11944 }
11945 
r_inv(double * x,int n)11946 bool r_inv(double * x,int n){
11947   giac::matrice M(n);
11948   doubleptr2matrice(x,n,n,M);
11949   M=giac::minv(M,giac::context0);
11950   return matrice2doubleptr(M,x);
11951 }
11952 
11953 
r_rref(double * x,int n,int m)11954 bool r_rref(double * x,int n,int m){
11955   giac::matrice M(n);
11956   doubleptr2matrice(x,n,m,M);
11957   giac::gen g=giac::_rref(M,giac::context0);
11958   if (g.type!=giac::_VECT)
11959     return false;
11960   return matrice2doubleptr(*g._VECTptr,x);
11961 }
11962 
r_det(double * x,int n)11963 double r_det(double *x,int n){
11964   giac::matrice M(n);
11965   doubleptr2matrice(x,n,n,M);
11966   giac::gen g=giac::mdet(M,giac::context0);
11967   g=giac::evalf_double(g,1,giac::context0);
11968   double d=1.0,e=1.0;
11969   if (g.type!=_DOUBLE_)
11970     return 0.0/(d-e);
11971   return g._DOUBLE_val;
11972 }
11973 
c_complexptr2matrice(c_complex * x,int n,int m,giac::matrice & M)11974 void c_complexptr2matrice(c_complex * x,int n,int m,giac::matrice & M){
11975   M.resize(n);
11976   for (int i=0;i<n;++i){
11977     if (m==0){
11978       M[i]=gen(x->r,x->i);
11979       ++x;
11980       continue;
11981     }
11982     M[i]=giac::vecteur(m);
11983     giac::vecteur & w=*M[i]._VECTptr;
11984     for (int j=0;j<m;++j){
11985       w[j]=gen(x->r,x->i);
11986       ++x;
11987     }
11988   }
11989 }
11990 
gen2c_complex(giac::gen & g)11991 c_complex gen2c_complex(giac::gen & g){
11992   double d=1.0,e=1.0;
11993   c_complex c={0,0};
11994   if (g.type!=giac::_DOUBLE_ && g.type!=giac::_CPLX)
11995     c.r=c.i=0.0/(d-e);
11996   else {
11997     if (g.type==giac::_DOUBLE_)
11998       c.r=g._DOUBLE_val;
11999     else {
12000       if (g.subtype!=3)
12001 	c.r=c.i=0.0/(d-e);
12002       c.r=g._CPLXptr->_DOUBLE_val;
12003       c.i=(g._CPLXptr+1)->_DOUBLE_val;
12004     }
12005   }
12006   return c;
12007 }
12008 
12009 // x must have enough space!
matrice2c_complexptr(const giac::matrice & M,c_complex * x)12010 bool matrice2c_complexptr(const giac::matrice &M,c_complex *x){
12011   int n=M.size();
12012   if (n==0)
12013     return false;
12014   if (M.front().type!=giac::_VECT){
12015     for (int i=0;i<n;++i){
12016       giac::gen g =giac::evalf_double(M[i],1,giac::context0);
12017       if (g.type!=giac::_DOUBLE_ && g.type!=giac::_CPLX)
12018 	return false;
12019       *x=gen2c_complex(g);
12020       ++x;
12021     }
12022     return true;
12023   }
12024   int m=M.front()._VECTptr->size();
12025   for (int i=0;i<n;++i){
12026     if (M[i].type!=giac::_VECT || M[i]._VECTptr->size()!=m)
12027       return false;
12028     giac::vecteur & w=*M[i]._VECTptr;
12029     for (int j=0;j<m;++j){
12030       giac::gen g =giac::evalf_double(w[j],1,giac::context0);
12031       if (g.type!=giac::_DOUBLE_ && g.type!=giac::_CPLX)
12032 	return false;
12033       *x=gen2c_complex(g);
12034       ++x;
12035     }
12036   }
12037   return true;
12038 }
12039 
c_inv(c_complex * x,int n)12040 bool c_inv(c_complex * x,int n){
12041   giac::matrice M(n);
12042   c_complexptr2matrice(x,n,n,M);
12043   M=giac::minv(M,giac::context0);
12044   return matrice2c_complexptr(M,x);
12045 }
12046 
c_proot(c_complex * x,int n)12047 bool c_proot(c_complex * x,int n){
12048   giac::matrice M(n);
12049   c_complexptr2matrice(x,n,0,M);
12050   M=giac::proot(M);
12051   return matrice2c_complexptr(M,x);
12052 }
12053 
c_pcoeff(c_complex * x,int n)12054 bool c_pcoeff(c_complex * x,int n){
12055   giac::matrice M(n);
12056   c_complexptr2matrice(x,n,0,M);
12057   M=giac::pcoeff(M);
12058   return matrice2c_complexptr(M,x);
12059 }
12060 
c_fft(c_complex * x,int n,bool inverse)12061 bool c_fft(c_complex * x,int n,bool inverse){
12062 #if 1
12063   complex<double> * X=(complex<double> *) x;
12064   double theta=2*M_PI/n;
12065   if (!inverse)
12066     theta=-theta;
12067   fft2(X,n,theta);
12068   if (inverse){
12069     for (int i=0;i<n;++i)
12070       X[i]=X[i]/double(n);
12071   }
12072   return true;
12073 #else
12074   giac::matrice M(n);
12075   c_complexptr2matrice(x,n,0,M);
12076   gen g=inverse?giac::_ifft(M,giac::context0):giac::_fft(M,giac::context0);
12077   if (g.type!=_VECT)
12078     return false;
12079   return matrice2c_complexptr(*g._VECTptr,x);
12080 #endif
12081 }
12082 
c_egv(c_complex * x,int n)12083 bool c_egv(c_complex * x,int n){
12084   giac::matrice M(n);
12085   c_complexptr2matrice(x,n,n,M);
12086   gen g=giac::_egv(M,giac::context0);
12087   if (!ckmatrix(g))
12088     return false;
12089   return matrice2c_complexptr(*g._VECTptr,x);
12090 }
12091 
c_eig(c_complex * x,c_complex * d,int n)12092 bool c_eig(c_complex * x,c_complex * d,int n){
12093   giac::matrice M(n);
12094   c_complexptr2matrice(x,n,n,M);
12095   gen g=giac::_jordan(M,giac::context0);
12096   if (g.type!=_VECT || g._VECTptr->size()!=2 || !ckmatrix(g[0]) || !ckmatrix(g[1]))
12097     return false;
12098   return matrice2c_complexptr(*g[0]._VECTptr,x) && matrice2c_complexptr(*g[1]._VECTptr,d);
12099 }
12100 
c_rref(c_complex * x,int n,int m)12101 bool c_rref(c_complex * x,int n,int m){
12102   giac::matrice M(n);
12103   c_complexptr2matrice(x,n,m,M);
12104   giac::gen g=giac::_rref(M,giac::context0);
12105   if (g.type!=giac::_VECT)
12106     return false;
12107   return matrice2c_complexptr(*g._VECTptr,x);
12108 }
12109 
c_det(c_complex * x,int n)12110 c_complex c_det(c_complex *x,int n){
12111   giac::matrice M(n);
12112   c_complexptr2matrice(x,n,n,M);
12113   giac::gen g=giac::mdet(M,giac::context0);
12114   g=giac::evalf_double(g,1,giac::context0);
12115   return gen2c_complex(g);
12116 }
12117 
c_sprint_double(char * s,double d)12118 void c_sprint_double(char * s,double d){
12119   giac::sprint_double(s,d);
12120 }
12121 
12122 // auto-shutdown
do_shutdown()12123 int do_shutdown(){
12124   xcas::save_console_state_smem("session.xw.tns",giac::context0);
12125 #ifdef NO_STDEXCEPT
12126   return 1;
12127 #else
12128   throw autoshutdown();
12129 #endif
12130 }
12131 
12132 // string translations
12133 #ifdef NUMWORKS
12134 #include "numworks_translate.h"
12135 #else
12136 #include "aspen_translate.h"
12137 #endif
tri2(const char4 & a,const char4 & b)12138 bool tri2(const char4 & a,const char4 & b){
12139   int res= strcmp(a[0],b[0]);
12140   return res<0;
12141 }
12142 
giac2aspen(int lang)12143 int giac2aspen(int lang){
12144   switch (lang){
12145   case 0: case 2:
12146     return 1;
12147   case 1:
12148     return 3;
12149   case 3:
12150     return 5;
12151   case 6:
12152     return 7;
12153   case 8:
12154     return 2;
12155   case 5:
12156     return 4;
12157   }
12158   return 0;
12159 }
12160 
gettext(const char * s)12161 const char * gettext(const char * s) {
12162   // 0 and 2 english 1 french 3 sp 4 el 5 de 6 it 7 tr 8 zh 9 pt
12163   int aspenlang=giac2aspen(lang);
12164   char4 s4={s};
12165   std::pair<char4 * const,char4 *const> pp=equal_range(aspen_giac_translations,aspen_giac_translations+aspen_giac_records,s4,tri2);
12166   if (pp.first!=pp.second &&
12167       pp.second!=aspen_giac_translations+aspen_giac_records &&
12168       (*pp.first)[aspenlang]){
12169     return (*pp.first)[aspenlang];
12170   }
12171   return s;
12172 }
12173 
12174 #endif // KHICAS
12175