001 #include "Utils.HC";
002 #include "RuleSet.HC";
003 #include "FileBMP.HC";
004 U0 CalcBezier(CD3I32 *point,CD3I32 *l,CD3I32 *cent,CD3I32 *r) {
005   point->x=2.*cent->x-l->x/2.-r->x/2.;
006   point->y=2.*cent->y-l->y/2.-r->y/2.;
007 }
008 //Returns maximum y
009 F64 GrPreciseBezier(CDC *dc,CD3I32 *ctrls,F64 *highest_x_pos=NULL) {
010   F64 x=ctrls[2].x,y=ctrls[2].y,x2,y2,step;
011   F64 max_y=y;
012   F64 max_x=x;
013   for(step=1/100.;step<=1;step+=1./100.) {
014     x2=ctrls[0].x*step`2+ctrls[1].x*2*step*(1-step)+ctrls[2].x*(1-step)`2;
015     y2=ctrls[0].y*step`2+ctrls[1].y*2*step*(1-step)+ctrls[2].y*(1-step)`2;
016     GrLine3(dc,x,y,0,x2,y2,0);
017     x=x2,y=y2;
018     if(y>=max_y) {
019       max_y=y;
020       max_x=x;
021     }
022   }
023   if(highest_x_pos) *highest_x_pos=max_x;
024   return max_y;
025 }
026 U0 QuessCenter(CD3I32 *middle,CD3I32 *l,CD3I32 *r,
027         F64 desired_x,F64 desired_y,F64 l_min_deriv=0.,
028         F64 r_min_deriv=0.) {
029   F64 at,closest_at,closest;
030   Bool tried_up=FALSE,tried_down=FALSE;
031   I64 sign=1,quessed_x,quessed_y;
032   F64 deriv,step;
033 //Quess y vertex cordnate
034   closest_at=l->y;step=l->y;
035   closest=F64_MAX;
036   while(!tried_up||!tried_down) {
037     middle->y=step;
038     CalcBezier(middle,l,middle,r);
039     at=l->y*0.5`2+middle->y*2*.5*.5+r->y*.5`2;
040 //left deritive
041     if(2.*Abs(at-l->y)>=l_min_deriv)
042       if(2.*Abs(r->y-at)>=r_min_deriv) {
043         if(Abs(at-desired_y)<closest) {
044           closest_at=step;
045           closest=Abs(at-desired_y);
046         }
047         if(at>desired_y) {
048           sign=-1;
049           tried_up=TRUE;
050         } else if(at<desired_y) {
051           sign=1;
052           tried_down=TRUE;
053         } else
054           break;
055       }
056     step+=sign;
057   }
058   quessed_y=closest_at;
059 //Guess x cordnate
060   tried_down=FALSE,tried_up=FALSE;
061   closest_at=l->x;
062   step=l->x;
063   closest=F64_MAX;
064   while(!tried_up||!tried_down) {
065     middle->x=step;
066     CalcBezier(middle,l,middle,r);
067     at=l->x*0.5`2+middle->x*2*.5*.5+r->x*.5`2;
068     if(Abs(at-desired_x)<closest) {
069       closest_at=step;
070       closest=Abs(at-desired_y);
071     }
072     if(at>desired_x) {
073       sign=-1;
074       tried_up=TRUE;
075     } else if(at<desired_x) {
076       sign=1;
077       tried_down=TRUE;
078     } else
079       break;
080     step+=sign;
081   }
082   quessed_x=closest_at;
083   middle->x=quessed_x,middle->y=quessed_y;
084 }
085 class CDisplayNode {
086   AST *ast;
087   CD2 hover_node_pos;
088   F64 handle_x,handle_y;
089   F64 bound_l,bound_r;
090   F64 max_y;
091   F64 l_deriv,r_deriv;
092   I32 color,thick;
093   I64 level;
094   I64Set *connects;
095 };
096 U0 DisplayNodeDel(CDisplayNode *n) {
097   I64 i;
098   if(n->connects) {
099     i=n->connects->cnt;
100     while(--i>=0)
101      DisplayNodeDel(n->connects->body[i]);
102   }
103   Free(n);
104 }
105 CTrie *DisplayNodeGetHoverWord(CDisplayNode *n,I64 ms_x,I64 ms_y) {
106   I64 i;
107   AST *ret;
108   if(n->ast&&Sqrt(Sqr(ms_x-n->hover_node_pos.x)+Sqr(ms_y-n->hover_node_pos.y))<16) {
109     return n->ast->word;
110   }
111   if(n->connects) {
112     i=n->connects->cnt;
113     while(--i>=0)
114      if(ret=DisplayNodeGetHoverWord(n->connects->body[i],ms_x,ms_y)) {
115        return ret;
116      }
117   }
118   return NULL;
119 }
120 
121 #define WORD_MARGIN 20
122 #define CURVE_MARGIN 40
123 class CDisplayTmp {
124   I64 *word_offsets;
125   F64 xoff,yoff,max_y;
126 };
127 F64 Center(F64 a,F64 b) {
128   return Min(a,b)+(Max(a,b)-Min(a,b))/2;
129 }
130 //Returns maximum 4 drawn
131 F64 DrawConnect(CDC *dc,I64 level=0,F64 x,F64 y,F64 x2,F64 y2,F64 mdl,F64 mdr,F64 *vx=NULL,F64 *vy=NULL,F64 *dl=NULL,F64 *dr=NULL,F64 *zenith_x) {
132   F64 highest;
133   CD3I32 ctrls[3];
134   ctrls[0].x=x;
135   ctrls[0].y=y;
136   ctrls[2].x=x2;
137   ctrls[2].y=y2;
138   QuessCenter(&ctrls[1],&ctrls[0],&ctrls[1],Center(x2,x),Max(y2,y)+CURVE_MARGIN*level,mdl,mdr);
139   dc->thick=3;
140   highest=GrPreciseBezier(dc,ctrls,zenith_x);
141   if(vx) *vx=ctrls[0].x*.5`2+ctrls[1].x*2*.5*(1-.5)+ctrls[2].x*.5`2;
142   if(vy) *vy=ctrls[0].y*.5`2+ctrls[1].y*2*.5*(1-.5)+ctrls[2].y*.5`2;
143   if(dl) *dl=2.*(ctrls[1].y-ctrls[0].y);
144   if(dr) *dr=2.*(ctrls[2].y-ctrls[1].y);
145   return highest;
146 }
147 I64 SideSort(AST *a,AST *b) {
148   return a->word_idx-b->word_idx;
149 }
150 I64 SideSortRev(AST *a,AST *b) {
151   return b->word_idx-a->word_idx;
152 }
153 //Fs->user_data has the distance we are measuring from
154 I64 DistSort(AST *a,AST *b) {
155   return AbsI64(a->word_idx-Fs->user_data)-AbsI64(b->word_idx-Fs->user_data);
156 }
157 
158 I64 DrawWordInfo(CDC *dc,I64 x,I64 y,CTrie *word,Bool dummy=FALSE) {
159   I64 ox=x;
160   if(dummy) dc=DCNew(1,1);
161   if(word->flags&(NOUN|PRONOUN|ADJECTIVE)) {
162     dc->color=GREEN;
163     if(word->flags&MASCULINE) {
164       GrPrint(dc,x,y,"M");
165       x+=8;
166     } else if(word->flags&FEMININE) {
167       GrPrint(dc,x,y,"F");
168       x+=8;
169     } else if(word->flags&NEUTER) {
170       GrPrint(dc,x,y,"N");
171       x+=8;
172     }
173 
174     dc->color=PURPLE;
175     if(word->flags&COMPARATIVE) {
176       GrPrint(dc,x,y,"Comp");
177       x+=8*4;
178     } else if(word->flags&COMPARATIVE) {
179       GrPrint(dc,x,y,"Sup");
180       x+=8*3;
181     }
182     if(word->flags&NOMITIVE) {
183       dc->color=LTGREEN;
184       GrPrint(dc,x,y,"N");
185       x+=8;
186     } else if(word->flags&ACCUSATIVE) {
187       dc->color=LTRED;
188       GrPrint(dc,x,y,"A");
189       x+=8;
190     } else if(word->flags&GENITIVE) {
191       dc->color=LTCYAN;
192       GrPrint(dc,x,y,"G");
193       x+=8;
194     } else if(word->flags&ABLATIVE) {
195       dc->color=LTBLUE;
196       GrPrint(dc,x,y,"Ab");
197       x+=8*2;
198     }
199 
200 _p_cnt:
201     dc->color=RED;
202     if(word->flags&_3P) {
203       GrPrint(dc,x,y,"3");
204       x+=8;
205     } else if(word->flags&_2P) {
206       GrPrint(dc,x,y,"2");
207       x+=8;
208     } else if(word->flags&_1P) {
209       GrPrint(dc,x,y,"1");
210       x+=8;
211     }
212 
213     dc->color=BLACK;
214     if(word->flags&PLURAL) {
215       GrPrint(dc,x,y,"P");
216       x+=8;
217     } else {
218       GrPrint(dc,x,y,"S");
219       x+=8;
220     }
221   } else if(word->flags&VERB) {
222     dc->color=BLUE;
223     if(word->flags&IMPERFECT) {
224       GrPrint(dc,x,y,"Imp");
225       x+=8*3;
226     } else if(word->flags&FUTURE) {
227       GrPrint(dc,x,y,"Fut");
228       x+=8*3;
229     } else if(word->flags&PERFECT) {
230       GrPrint(dc,x,y,"Per");
231       x+=8*3;
232     } else if(word->flags&PLUPERFECT) {
233       GrPrint(dc,x,y,"Plu");
234       x+=8*3;
235     }
236     goto _p_cnt;
237   }
238   if(dummy) DCDel(dc);
239   return (x-ox)/8;
240 }
241 
242 
243 CDisplayNode *DisplayNode(CDisplayTmp *world,CDC *dc,AST *ast,I64 level=0,I64 *max_h=NULL) {
244   CDisplayNode *ret=CAlloc(sizeof CDisplayNode),*tmp;
245   ret->ast=ast;
246   ret->level=level;
247   ASTSet *set;
248   F64 x,y,ww=0,x2,y2,handle_x,handle_y;
249   F64 bound_y=F64_MIN;
250   I64 color=LTGRAY,idx,run,run2,idx2,old_color,old_color2;
251   I64Set *left_sides=NULL,*right_sides=NULL,*set2=NULL;
252   U8 *optr,*base_word;
253   I64 level2,max_level=0;
254   AST *ast2;
255   CD3I32 ctrls[3];
256   Bool is_left_side;
257   F64 max_l_deriv=0.,max_r_deriv=0.;
258   switch(ast->act_as_type) {
259       break;case AST_NOUN: color=GREEN;
260       break;case AST_CONJUNCTION: color=RED;
261       break;case AST_VERB: color=BLUE;
262       break;case AST_OF: color=BROWN;
263       break;case AST_WHERE: color=PURPLE;
264       break;case AST_ADJECTIVE: color=CYAN;
265       break;case AST_INFINITIVE: color=LTPURPLE;
266       break;case AST_MEASURE: color=LTGREEN;
267       break;case AST_ADVERB: color=LTCYAN;
268       break;case AST_QUESTION: color=LTGRAY;
269   }
270   old_color2=dc->color;
271   ret->color=color;
272   if(ast->word) {
273     y=8;
274     x=world->word_offsets[ast->word_idx];
275     dc->color=color;
276     if(ast->word->translation)
277       ww=FONT_WIDTH*MaxI64(StrLen(ast->word->str),StrLen(ast->word->translation));
278     else
279       ww=FONT_WIDTH*StrLen(ast->word->str);
280     x+=ww/2;
281     if(ast->word->front_declension||ast->word->back_declension) {
282       base_word=optr=StrNew(ast->word->str);
283       if(ast->word->back_declension)
284         base_word+=StrLen(ast->word->back_declension);
285       if(ast->word->front_declension)
286         base_word[StrLen(base_word)-StrLen(ast->word->front_declension)]=0;
287       x2=x-StrLen(ast->word->str)*8/2;
288       idx2=0;
289       if(ast->word->back_declension) {
290         dc->color=color^0x7;
291         GrPrint(dc,x2,y,"%s",ast->word->back_declension);
292         idx2+=StrLen(ast->word->back_declension);
293       }
294       dc->color=color;
295       GrPrint(dc,x2+8*idx2,y,"%s",base_word);
296       idx2+=StrLen(base_word);
297       if(ast->word->front_declension) {
298         dc->color=color^0x7;
299         GrPrint(dc,x2+8*idx2,y,"%s",ast->word->front_declension);
300         idx2+=StrLen(ast->word->front_declension);
301       }
302       dc->color=color;
303       Free(optr);
304     } else {
305       x2=x-StrLen(ast->word->str)*8/2;
306       GrPrint(dc,x2,y,"%s",ast->word->str);
307     }
308     x2=DrawWordInfo(NULL,x,y,ast->word,TRUE);//number of chars
309     x2=x-x2*8/2;
310     DrawWordInfo(dc,x2,y+1+FONT_HEIGHT,ast->word);
311     if(ast->word->translation) {
312       x2=x-StrLen(ast->word->translation)*8/2;
313       GrPrint(dc,x2,y+2+FONT_HEIGHT*2,"%s",ast->word->translation);
314     }
315     ret->hover_node_pos.x=x;
316     ret->hover_node_pos.y=y+3+FONT_HEIGHT*3+2.5;
317     GrFillCircle(dc,x,y+3+FONT_HEIGHT*3+2.5,0,5);
318     x2=x;
319     y2=y+3+FONT_HEIGHT*3+7;
320     ret->handle_x=x2;
321     ret->handle_y=y2;
322     ret->bound_l=x2;
323     ret->bound_r=x2;
324     ret->max_y=y2;
325     bound_y=y2;
326   } else
327     throw('Visual');
328 //I will sort the left and right sides by distance
329   for(run=0;run<=10;run++) {
330     if((set=ast->nomitive)&&run==0) {
331 ent:
332       for(idx=0;idx!=set->cnt;idx++) {
333         set2=I64SetAdd(set2,set->body[idx]);
334         if(set->body[idx](AST*)->word_idx<ast->word_idx)
335           left_sides=I64SetAdd(left_sides,set->body[idx]);
336         else
337           right_sides=I64SetAdd(right_sides,set->body[idx]);
338       }
339     } else if((set=ast->accusative)&&run==1) {
340       goto ent;
341     } else if((set=ast->dative)&&run==2) {
342       goto ent;
343     } else if((set=ast->genitive)&&run==3) {
344       goto ent;
345     } else if((set=ast->adjective)&&run==4) {
346       goto ent;
347     } else if((set=ast->preposition)&&run==5) {
348       goto ent;
349     } else if((set=ast->conjunction)&&run==6) {
350       goto ent;
351     } else if((set=ast->measurement)&&run==7) {
352       goto ent;
353     } else if((set=ast->adverb)&&run==8) {
354       goto ent;
355     } else if((set=ast->ablative)&&run==9) {
356       goto ent;
357     }else if((set=ast->question)&&run==10) {
358       goto ent;
359     }
360   }
361 //Sort the left and right sides
362   if(left_sides)
363     QSortI64(left_sides->body,left_sides->cnt,&SideSortRev);
364   if(right_sides)
365     QSortI64(right_sides->body,right_sides->cnt,&SideSort);
366   if(set2) {
367     Fs->user_data=ast->word_idx;
368     QSortI64(set2->body,set2->cnt,&DistSort);
369   }
370   set=set2;
371   if(set)
372     for(idx=0;idx!=set->cnt;idx++) {
373       if(I64SetHasItem(ast->nomitive,set->body[idx]))
374         dc->color=LTGREEN;
375       else if(I64SetHasItem(ast->accusative,set->body[idx]))
376         dc->color=LTRED;
377       else if(I64SetHasItem(ast->dative,set->body[idx]))
378         dc->color=LTCYAN;
379       else if(I64SetHasItem(ast->genitive,set->body[idx]))
380         dc->color=BROWN;
381       else if(I64SetHasItem(ast->adjective,set->body[idx]))
382         dc->color=BLUE;
383       else if(I64SetHasItem(ast->preposition,set->body[idx]))
384         dc->color=LTGRAY;
385       else if(I64SetHasItem(ast->conjunction,set->body[idx]))
386         dc->color=RED;
387       else if(I64SetHasItem(ast->measurement,set->body[idx]))
388         dc->color=PURPLE;
389       else if(I64SetHasItem(ast->adverb,set->body[idx]))
390         dc->color=CYAN;
391       else if(I64SetHasItem(ast->ablative,set->body[idx]))
392         dc->color=BLACK;
393       else if(I64SetHasItem(ast->question,set->body[idx]))
394         dc->color=DKGRAY;
395       if(I64SetHasItem(left_sides,set->body[idx])) {
396         is_left_side=TRUE;
397         level2=0;
398         for(idx2=0;idx2!=left_sides->cnt;idx2++) {
399           ast2=left_sides->body[idx2];
400           if(ast2->disp_node)
401             level2=MaxI64(ast2->disp_node->level,level2);
402           if(ast2==set->body[idx])
403             break;
404         }
405       }
406       if(I64SetHasItem(right_sides,set->body[idx])) {
407         is_left_side=FALSE;
408         level2=0;
409         for(idx2=0;idx2!=right_sides->cnt;idx2++) {
410           ast2=right_sides->body[idx2];
411           if(ast2->disp_node)
412             level2=MaxI64(ast2->disp_node->level,level2);
413           if(ast2==set->body[idx])
414             break;
415         }
416       }
417       max_level=MaxI64(max_level,level2);
418       tmp=DisplayNode(world,dc,set->body[idx],level2+1);
419       set->body[idx](AST*)->disp_node=tmp;
420       ret->connects=I64SetAdd(ret->connects,tmp);
421 //ret->handle_y set here
422       if(is_left_side) {
423         world->max_y=Max(world->max_y,ret->handle_y=DrawConnect(dc,level2+1,tmp->handle_x,tmp->handle_y,x2,y2,0,max_l_deriv,&handle_x,&handle_y,&ret->l_deriv,&ret->r_deriv,&ret->handle_x));
424         max_l_deriv=Max(Abs(ret->r_deriv*.55),max_l_deriv); //our target node is on the left side,our current node is on the rgiht side
425       } else {
426         world->max_y=Max(world->max_y,ret->handle_y=DrawConnect(dc,level2+1,tmp->handle_x,tmp->handle_y,x2,y2,max_r_deriv,0,&handle_x,&handle_y,&ret->l_deriv,&ret->r_deriv,&ret->handle_x));
427         max_r_deriv=Max(Abs(ret->l_deriv*.55),max_r_deriv);  //our target node is on the right side,our current node is on the left side
428       }
429       ret->max_y=Max(ret->max_y,handle_y);
430       ret->bound_l=Min(ret->bound_l,tmp->bound_l);
431       ret->bound_r=Max(ret->bound_r,tmp->bound_r);
432       old_color=dc->color;
433       dc->color=BLACK;
434       GrFillCircle(dc,tmp->handle_x,tmp->handle_y,0,10);
435       dc->color=old_color;
436     }
437 //If we have connects of each side,make our connect in the "center"
438   if(left_sides&&left_sides->cnt&&right_sides&&right_sides->cnt) {
439     ret->handle_x=(ret->bound_r-ret->bound_l)/2.+ret->bound_l;
440     ret->handle_y=ret->max_y+8;
441   }
442   Free(left_sides),Free(right_sides);
443   dc->color=old_color2;
444   ret->level=level;
445   return ret;
446 }
447 
448 U0 CopyRegion(CDC *dst,CDC *img,I64 dx,I64 dy,I64 x,I64 y,I64 w,I64 h) {
449   I64 x2,y2;
450   for(x2=x;x2!=x+w;x2++) {
451     for(y2=y;y2!=y+h;y2++) {
452       dst->color=GrPeek(img,x2,y2);
453       if(dst->color==-1) dst->color=TRANSPARENT;
454       GrPlot(dst,dx+x2-x,dy+y2-y);
455     }
456   }
457 }
458 //Like "word-wrap" for images
459 CDC *SplitImageIntoColumn(CDC *img,I64 width=GR_WIDTH) {
460   I64 clip_cnt=img->width/width;
461   if(img->width%width)
462     clip_cnt++;
463   CDC *ret=DCNew(width,img->height*clip_cnt);
464   while(--clip_cnt>=0) {
465     CopyRegion(ret,img,0,clip_cnt*img->height,clip_cnt*width,0,width,img->height);
466   }
467   return ret;
468 }
469 
470 CDC *DrawSentence(AST *sentence,I64 word_cnt,U8 **words,I64 dwidth=I64_MAX,I64 *w=NULL,I64 *h=NULL,I64 ms_x=0,I64 ms_y=0,CTrie **hover_over=NULL) { 
471   I64 off,idx,inf_d,wc,cw;
472   CDC *dc,*wrapped;
473   I64 last_wrap=0,diff;
474   U8 *closest;
475   CDisplayTmp t;
476   CTrie **forms;
477   AST *untainted=ASTClone(sentence);
478   wc=ASTGetTrieWords(sentence,NULL);
479   forms=CAlloc(word_cnt*8);
480   ASTGetTrieWords(sentence,forms);
481   t.xoff=0,t.yoff=0;
482   t.word_offsets=MAlloc(word_cnt*8);
483   t.max_y=0.;
484   for(off=WORD_MARGIN,idx=0;idx!=word_cnt;idx++) {
485     cw=0;
486     if(forms[idx]) {
487       cw=StrLen(forms[idx]->str);
488       if(forms[idx]->translation)
489         cw=MaxI64(StrLen(forms[idx]->translation),cw);
490     }
491     t.word_offsets[idx]=off;
492     off+=FONT_WIDTH*cw;
493     off+=WORD_MARGIN;
494 //Make "image-wrap" points
495     if(idx) {
496       if(t.word_offsets[idx]-last_wrap+WORD_MARGIN>=dwidth) {
497         diff=t.word_offsets[idx]-t.word_offsets[idx-1];
498         t.word_offsets[idx-1]=(last_wrap=CeilI64(t.word_offsets[idx-1],dwidth))+WORD_MARGIN;
499         off=t.word_offsets[idx]=diff+t.word_offsets[idx-1];
500         off+=FONT_WIDTH*cw;
501         off+=WORD_MARGIN;
502       }
503     }
504   }
505   dc=DCNew(1,1);
506   DisplayNodeDel(DisplayNode(&t,dc,sentence));
507   DCDel(dc);
508   dc=DCNew(off+WORD_MARGIN,t.max_y+8+10+FONT_HEIGHT*4); //See DisplayNode
509   DCFill(dc,TRANSPARENT);
510 //DisplayNode will set ->display_node of the ast,so use the one without the ->display_node's
511   CDisplayNode *dn=DisplayNode(&t,dc,untainted);
512   if(hover_over) { 
513     hover_over[0]=DisplayNodeGetHoverWord(dn,ms_x,ms_y);
514   }
515   DisplayNodeDel(dn);
516   if(dwidth!=I64_MAX&&off+8>dwidth) {
517     wrapped=SplitImageIntoColumn(dc,dwidth);
518     DCDel(dc);
519   } else
520     wrapped=dc;
521   if(w) *w=dc->width;
522   if(h) *h=dc->height;
523   Free(t.word_offsets);
524   Free(forms);
525   ASTDel(untainted);
526   return wrapped;
527 }
528 WinMax;
529 U0 DumpSentence(...) {
530   try {
531   I64 *dummy_stk=MAlloc(8*(1+argc));
532   I64 w,h;
533   CDC *dc;
534   dummy_stk[0]=argc;
535   MemCpy(dummy_stk+1,argv,argc*8);
536   AST *sent=ParseSentenceJoin(argc+1,dummy_stk);
537   if(sent) {
538     dc=DrawSentence(sent,argc,argv);
539 "
540 
541 
542 
543 
544 
545 
546 
547 
548 
549 
550 
551 
552 ";
553     DocSprite(DocPut,DC2Sprite(dc));
554 "
555 
556 
557 
558 
559 
560 
561 
562 
563 
564 
565 
566 
567 ";
568     CFileBMP *bmp=BMPRLE4To(dc);
569     DCColorChg(dc,TRANSPARENT,WHITE);
570     FileWrite("sent.BMP",bmp,bmp->file_size);
571     Free(bmp);
572     DCDel(dc);
573     DumpAST(sent);
574     ASTDel(sent);
575   }
576   Free(dummy_stk);
577   } catch PutExcept(FALSE);
578 }
579 public Bool WordTextBox(CDC *dc=0,I64 x1,I64 y1,U8 *s,I64 bg_color=YELLOW)
580 {//3D. Transformation. DCF_SYMMETRY is silly.
581   U8 *ptr;
582   if(!dc) dc=gr.dc;
583   I64 ch,res,w,w_max,h;
584   I64 old=dc->color;
585   I64 border=2;
586   if (!s) return FALSE;
587   ptr=s;
588   w=0;  w_max=0; h=FONT_HEIGHT;
589 
590   while (ch=*ptr++) {
591     if (ch=='\t')
592       w=CeilU64(w+FONT_WIDTH,FONT_WIDTH*8);
593     else if (ch=='\n') {
594       if (w>w_max) w_max=w;
595       w=0;
596       h+=FONT_HEIGHT;
597     } else
598       w+=FONT_WIDTH;
599   }
600   if (w>w_max) w_max=w;
601   dc->color=bg_color;
602   GrRect(dc,x1-border,y1-border,w_max+border<<1,h+border<<1);
603   dc->color=old;
604   res=GrPrint(dc,x1,y1,"%s",s);
605   res|=GrLine(dc,x1-border         ,y1-border  ,x1+w_max+border,y1-border);
606   res|=GrLine(dc,x1-border         ,y1+h+border,x1+w_max+border,y1+h+border);
607   res|=GrLine(dc,x1-border         ,y1-border  ,x1-border,y1+h+border);
608   res|=GrLine(dc,x1+w_max+border,y1-border  ,x1+w_max+border,y1+h+border);
609 
610   return !!(res);
611 }
612 
613 
614 
615 U0 InteractViewDrawIt(CTask *t,CDC *dc) {
616   U8 *st;
617   U8 *tran;
618   U8 **toks;
619   I64 tcnt;
620   AST *ast;
621   CTrie *word=NULL;
622   CDC *dc2;
623   CDoc *d=DocNew;
624   I64 x,y;
625   if(ast=FramePtr("InteractAst",t)) {
626     if(st=FramePtr("InteractText",t)) {
627     toks=TokenizeSentence(st,&st);
628     tcnt=0;
629     while(toks[tcnt])
630       tcnt++;
631     ast=ASTClone(ast);
632     dc2=DrawSentence(ast,tcnt,toks,,,,x=ms.pos.x-t->pix_left,y=ms.pos.y-t->pix_top,&word);
633     GrBlot(dc,0,0,dc2);
634     dc->color=RED;
635     if(word&&word->str) {
636       DocPrint(d,"Word %s:\n",word->str);
637       if(tran=GetTranslation(word->str,TRUE)) {
638         DocPrint(d,"Defs:\n%s\n",tran);
639         Free(tran);
640       }
641 
642 //No declensions (like numbers that dont decline)
643 /*#define INDECLINABLE (1<<32)
644 #define PRESENT (1<<33)
645 #define PASSIVE (1<<34)
646 #define IMPERATIVE (1<<35)
647 #define PARTICIPLE (1<<36)
648 #define GERUND (1<<37)
649 #define COMPARATIVE (1<<38)
650 #define SUPERLATIVE (1<<39)
651 #define PARTICLE (1<<40)
652 #define CONJUNCTION2 (1<<41) //dixeque Words ending in -que
653 #define IS (1<<42) //Words like sum
654 #define DETIRMINER (1<<43) //things *that* are green */
655       if(word->flags&NOMITIVE)
656         DocPrint(d,"Nom.\n");
657       if(word->flags&GENITIVE)
658         DocPrint(d,"Gen.\n");
659       if(word->flags&DATIVE)
660         DocPrint(d,"Dat.\n");
661       if(word->flags&ACCUSATIVE)
662         DocPrint(d,"Acc.\n");
663       if(word->flags&ABLATIVE)
664         DocPrint(d,"Abl.\n");
665       if(word->flags&SINGULAR)
666         DocPrint(d,"Sing.\n");
667       if(word->flags&PLURAL)
668         DocPrint(d,"Plrl.\n");
669       if(word->flags&FEMININE)
670         DocPrint(d,"Fem.\n");
671       if(word->flags&MASCULINE)
672         DocPrint(d,"Masc.\n");
673       if(word->flags&INFINITIVE)
674         DocPrint(d,"Inf.\n");
675       if(word->flags&_1P)
676         DocPrint(d,"1st.\n");
677       if(word->flags&_2P)
678         DocPrint(d,"2nd.\n");
679       if(word->flags&_3P)
680         DocPrint(d,"3rd.\n");
681       if(word->flags&IMPERFECT)
682         DocPrint(d,"Imperfect.\n");
683       if(word->flags&FUTURE)
684         DocPrint(d,"Fut.\n");
685       if(word->flags&CONJUNCTION)
686         DocPrint(d,"Conj.\n");
687       if(word->flags&VERB)
688         DocPrint(d,"V.\n");
689       if(word->flags&NOUN)
690         DocPrint(d,"N.\n");
691       if(word->flags&ADVERB)
692         DocPrint(d,"Adv.\n");
693       if(word->flags&ADJECTIVE)
694         DocPrint(d,"Adj.\n");
695       if(word->flags&PRONOUN)
696         DocPrint(d,"Pron.\n");
697       if(word->flags&REFLEXIVE)
698         DocPrint(d,"Reflex.\n");
699       if(word->flags&POSSESIVE)
700         DocPrint(d,"Poss.\n");
701       if(word->flags&DEMONSTRATIVE)
702         DocPrint(d,"Demon.\n");
703       if(word->flags&INTEROGITIVE)
704         DocPrint(d,"Inter.\n");
705       if(word->flags&NEUTER)
706         DocPrint(d,"Neut.\n");
707       if(word->flags&RELATIVE)
708         DocPrint(d,"Rel.\n");
709       if(word->flags&PREPOSITION)
710         DocPrint(d,"Prep.\n");
711       if(word->flags&PERFECT)
712         DocPrint(d,"Per.\n");
713       if(word->flags&PLUPERFECT)
714         DocPrint(d,"Plu.\n");
715       if(word->flags&SUBJUNCTIVE)
716         DocPrint(d,"Sub.\n");
717         
718       tran=DocSave(d);
719       WordTextBox(dc,x,y,StrUtil(tran,SUF_REM_CTRL_CHARS));
720       Free(tran);
721     }
722     ASTDel(ast);
723     DCDel(dc2);
724     tcnt=0;
725     while(toks[tcnt])
726       Free(toks[tcnt++]);
727     Free(toks);
728     }
729   }
730   DocDel(d);
731 }
732 U0 InteractView(U8 *st) {
733   U8 **toks;
734   I64 tcnt;
735   AST *ast;
736   SettingsPush;
737   DocClear;
738   FramePtrAdd("InteractText",st);
739   toks=TokenizeSentence(st,&st);
740   tcnt=0;
741   while(toks[tcnt])
742     tcnt++;
743   ast=ParseSentenceJoin(tcnt,toks);
744   if(!ast) goto fin;
745   Fs->draw_it=&InteractViewDrawIt;
746 "
747 
748 
749 ";
750 DumpAST(ast);
751   FramePtrAdd("InteractAst",ast);
752   while(ast&&GetKey!=CH_ESC)
753     Refresh;
754   
755 fin:
756   tcnt=0;
757   while(toks[tcnt])
758     Free(toks[tcnt++]);
759   Free(toks);
760   ASTDel(ast);
761   SettingsPop;
762 }
763 U0 DumpSentences(U8 *st,U8 *translations=NULL) {
764   U8 **toks;
765   I64 tcnt;
766   I64 w=0,h=0;
767   AST *ast;
768   CDC *dc,*tmp_dc;
769   CDC *sents[0x800];
770   I64 sent_cnt=0;
771   U8 *tmp;
772   CFileBMP *bmp;
773   while(*SkipWhitespace(st)) {
774     tcnt=0;
775     toks=TokenizeSentence(st,&st);
776     while(toks[tcnt]) {
777       tcnt++;
778     }
779     ast=ParseSentenceJoin(tcnt,toks);
780     if(ast) {
781       dc=DrawSentence(ast,tcnt,toks);
782 "
783 
784 
785 
786 
787 
788 
789 
790 
791 
792 
793 
794 
795       ";
796       DocSprite(DocPut,DC2Sprite(dc));
797 "
798 
799 
800 
801 
802 
803 
804 
805 
806 
807 
808 
809 
810       ";
811       sents[sent_cnt++]=dc;
812       w=MaxI64(dc->width,w);
813       h+=dc->height;;
814     }
815     tcnt=0;
816     while(toks[tcnt])
817       Free(toks[tcnt++]);
818     Free(toks);
819   }
820   if(translations) {
821     tcnt=0;
822     while(tmp=LstSub(tcnt,translations)) {
823       if(8*StrLen(tmp)>w)
824         w=8*StrLen(tmp);
825       tcnt++;
826     }
827     h+=tcnt*25;
828   }
829   dc=DCNew(w,h);
830   DCFill(dc,WHITE);
831   h=0;
832   for(tcnt=0;tcnt<sent_cnt;tcnt++) {
833     tmp_dc=sents[tcnt];
834     w=dc->width/2.-tmp_dc->width/2.;
835     GrBlot(dc,w,h,tmp_dc);
836     h+=tmp_dc->height;
837     if(translations) {
838       if(tmp=LstSub(tcnt,translations)) {
839         w=dc->width/2.-8*StrLen(tmp)/2.;
840         dc->color=BLACK;
841         GrPrint(dc,w,h+(25-8)/2.,"%s",tmp);
842         h+=25;
843       }
844     }
845     DCDel(tmp_dc);
846   }
847   bmp=BMPRLE4To(dc); 
848   FileWrite("sent.BMP",bmp,bmp->file_size);
849   Free(bmp);
850   DCDel(dc);
851 }
852 
853 DocMax;
854 /*
855 
856 DumpSentences(
857   "laicalis nisi hos quinque pericula et comminationes sunt dimittere sed nos perditus et nos cedere inferno."
858   "[ quid quinque ] es [ [ Mortificatio animales ] et surreptio et [ peccare sexualiter ] et mendacium et [ alcohol illa inportet neglegentiam]]."
859   "Nisi [ [ hos quinque pericula et comminationes ] sunt dimittere ] nisi [ nos sunt perditus ] et [ nos cedere inferno ]."
860 ,
861 "Householder, unless these five dangers and threats are given up, one is said to be unethical, and one goes to hell\0"
862 "What five? Killing living creatures, stealing, committing sexual misconduct, lying, and using alcoholic drinks that cause negligence\0"
863 "Unless these five dangers and threats are given up, one is said to be unethical, and one goes to hell\0"
864 );
865 */
866 /*DumpSentences(
867         "Erema est symbolum  pro [ siccitas et infelix ]  de dormire animam."
868         "[uva catervae] est [[symbolum pro schola scholarium]  quia [initiati surgere  conjuncte in solum rami]] ." 
869         "Tu non oportet [ interficere animales vel furari vel potare alcohol ]."
870         "Audio tibi et amo tibi."
871         "namque [  Grinch sum cupere [coleum huius]].",
872         "The desert is a symbol for the aridity and unproductivity of the unawakened consciousness.\0"
873         "The grape cluster is a symbol for the school of adepts, for the initiates grow together upon a single branch\0"
874         "You shouldn't kill living creatures, or steal,or lie, or drink alcohol.\0"
875 );*/
876 
877 /*DumpSentences(
878 "sancti entia in decem regiones es."
879 "numerosus sicut [harenae [fluminis ganges]] es." // ...
880 "insimul adlaudant  [inopinabilissimus et [altissimam sanctus] dominum  Amitaiyus]."
881 "[[Omne ens] qui [audiant id nomen]] et [laetant in fidem]."
882 "cogitent eius solus semel."
883 "eorum devoveant [[meritum renato] [in illum sanctum agrum]]."
884 "adfecto [[renato illum]  et  [potiri renatum]  et [potiri salvationem]]." //
885 ,
886 "All the Holy Ones in the ten directions,\0"
887 "as numerous as the sands of the Ganges River\0"
888 "together praise the inconceivable, supernal virtue of Lord Amitayus\0"
889 "All sentient beings who, having heard his Name, rejoice in faith,\0"
890 " think of him even once,\0"
891 "and sincerely devote the merit of virtuous practices to rebirth in that holy land,\0"
892 //aspiring to be reborn there, will attain rebirth and attain salvation. But excluded are those who have committed the five cardinal sins and violated the holy law."
893 );*/
894 /*
895 DumpSentences(
896 " [in principio] creavit Deus caelum et terram."
897 "[terra erat [inanis et vacua]] et [[tenebrae super faciem ]  et spiritus Dei ferebatur super aquas]."
898 "[dixitque Deus] quod [[fiat lux] et [facta est lux]]."
899 "et [[vidit Deus lucem] quod [esset bona]] et [divisit lucem ac tenebras]."
900 "[appellavitque quod [[lucem diem es] et [tenebras noctem es] ]]."
901 ,
902 "In the beginning God created heaven, and earth.\0"
903 "And the earth was void and empty, and darkness was upon the face of the deep; and the spirit of God moved over the waters.\0"
904 "And God said: Be light made. And light was made.\0"
905 "And God saw the light that it was good; and he divided the light from the darkness.\0"
906 "And he called the light Day, and the darkness Night; and there was evening and morning one day. \0"
907 );
908 */
909 //DumpSentences("Es [optumus situs] [interretialis finctus].","Is the best site of the false internet!");
910 
911 
912 //DumpSentences("Benedicere te. Spero potioris pacem aeternam et laetitiam.");
913 /*DumpSentences(
914         "namque [  Grinch sum cupere [coleum huius]].",
915         "Truly,The Grinch's sack Is what I want"
916 );*/
917 /*DumpSentences(
918 "*[ omnis sancti entia in decem regiones] es.",
919 "Poop\0"
920 );*/
921 //
922 //DumpSentence("quomondo","es","tuum","sapor","[","camelus","lotii","]");;
923 //DumpSentence("[","tu","ne","cede","malis","]","sed","contra","audentior","ito"); 
924 //DumpSentence("Spero","potioris","pacem","aeternam","et","laetitiam");
925 //DumpSentence("nisi","[","canto","]","sed","audio");
926 //DumpSentence("laicalis","nisi","hos","quinque","pericula","et","comminationes","sunt","dimittere","sed","nos","perditus","et","nos","cedere","inferno");
927 //DumpSentence("[","quid","quinque","]","es","[","[","Mortificatio","animales","]","et","surreptio","et","[","peccare","sexualiter","]","et","mendacium","et","[","alcohol","illa","inportet","neglegentiam","]","]");
928 //DumpSentence("Nisi","[","[","hos","quinque","pericula","et","comminationes","]","sunt","dimittere","]","nisi","[","nos","sunt","perditus","]","et","[","nos","cedere","inferno","]");
929 //
930 /*DumpSentence("portat");
931 DumpSentence("portat","saxa","puella","in","aqua");
932 DumpSentence("cibum","et","aquam","portabo","ad","triclinium");
933 DumpSentence("cibum","portatis","et","aquam","gustant","sed","vinum","amamus");
934 DumpSentence("agricolae","saxa","invenient");
935 DumpSentence("servi","et","puellae","reginam","audiebant");
936 DumpSentence("in","triclinio","cibum","paramus");
937 DumpSentence("quomondo","aquam","portabis");
938 DumpSentence("quis","est");
939 DumpSentence("cum","amico","in","silva","ambulo");
940 DumpSentence("ex","silva","ad","villam","festinabo","et","cum","amico","in","cameram","ambulabo");
941 DumpSentence("nepos","noster","uxorem","cupit");
942 DumpSentence("non","edam","vivo","sed","ut","vivam","edo");*/
943 //Genesis 1
944 //DumpSentences("creavit terram  et terram");
945 //InteractView("edimus ut vivamus");
946 //InteractView("philosophia est vitae magistra");
947 //DumpSentences("assentatio  es [malus vitium]");
948 //DumpSentences("video hominem abire");
949 //DumpSentence("terra","erat","inanis","et","vacua","et","tenebrae","super","faciem","abyssi","et","spiritus","Dei","ferebatur","super","aquas");
950 //"si",
951 //DumpSentences("Omne qui ens audiant nomen.");
952 //DumpSentences("puella nominis  nominis es");
953 
954 // Nroot's Doctrine 1
955 DumpSentences("Res finitus sunt."
956         "Formamentum sunt haut."
957         "Res creat e [formamentis abditis]."
958         "Animi est abditi."
959         "animos sunt mutationes formamentorum."
960         "Mutatio formamentorum sunt  discursum."
961         "tela tenet unus  fila ilico. [duo fila existit haut]  ubi [unus existat]."
962         "sed fila existat juxta alius fila."
963         "[[unus corpus] teneat haut [alius positum]]."
964         "[corpus tenet diversum animos] quando [diversum positum existit]."
965         "[animus est juxta [diversum animos]] hac [tela tenet [diversum fila]."
966         "[idem animi ] sunt [[omnia animos] in [diversum positum]].");
967 //InteractView("decorum est pro patria mori");
968 //
969 //InteractView("in principio creavit Deus [caelum et  terram]");
970 //InteractView("Notitia est peior quam melior");
971 //DumpSentences("Notitia est peior quam melior");
972 //TrieAdd("Herodes",NOUN|NOMITIVE,"Herod");
973 //InteractView("tunc Herodes videns");
974 //DumpSentences("[[tunc Herodes videns] quoniam [inlusus esset a magis]] et [iratus est valde]");
975 // et mittens occidit omnes pueros qui erant in Bethleem et in omnibus finibus eius a bimatu et infra secundum tempus quod exquisierat a magis");