home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c100 / 1.ddi / SNAV0111.ZIP / SNAV1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-16  |  12.0 KB  |  356 lines

  1. // 28.7.89 avner ben - classified the alphabet datatypes
  2. //          ┌───────┐
  3. //    ─────────>│ AVNER │
  4. //    ─────────>│  BEN  │──────> Software Engineering Method
  5. //          └───────┘
  6. //    10 Dov-Hoz st. Tel-Aviv 63416 Israel tel. 972-3-221535
  7.  
  8. // The Screen NAVigator, ver 1.10 April 1990
  9. // Copyright (c) 1989 by Avner Ben
  10. // Snav is not, and never was, free software.
  11. // for conditions for use refer to file "copyrigh.txt"
  12.  
  13. // The Screen Navigator is an object-oriented device-independent
  14. // character-graphics driver package, written in the C++ language,
  15. // distributed in the form of C++ source code.
  16. // For further information refer to the documentation files.
  17.  
  18. // The user may not omit this text, from the beginning of the file, to
  19. // the line of asterisks below.
  20.  
  21. /***************************************************************************/
  22.  
  23. // package nucleus part 2 - source code.
  24. // This file defines the "computer-alphabet" object, and offers an
  25. // extended-ASCII implemented, as on the IBM-PC.
  26. // for data-structure logic, refer to file "article".
  27.  
  28. // History:
  29. // 28.7.89 avner ben coded.
  30. /////// snav v1.1
  31. // 5.3.90  avner ben - C++ v2.0 upgrade.
  32. //    *  removed Zortech-specific strupr()
  33. //    *  removed unnecessary #include to <conio.h>
  34.  
  35. // Site history (of this copy):
  36. // __.__.__ ____________ : __________________.
  37.  
  38. #include <stdio.h>
  39. #include <string.h>
  40.  
  41. #define  SNAV1_C
  42. #include "snav0.hpp"
  43. #include "snav1.hpp"
  44.  
  45. /**************** indexed access to character attribute table *****************/
  46.  
  47. int ascii_pc_data[]=
  48. { // in-memory file to be loaded into the default alphabet when initialized.
  49. //   all semigraphic characters in the ascii collating sequence, pc-extended.
  50.  
  51. //    num directions-connective   wgt
  52. //    --- ----------------------- ---
  53.      16,LTDIR,            3,0, // default right arrow
  54.      17,RTDIR,            3,0, // default left arrow
  55.      30,DNDIR,            0,3, // default up arrow
  56.      31,UPDIR,            0,3, // default down arrow
  57.      43,RTDIR|UPDIR|LTDIR|DNDIR,0,0, // twg cross
  58.      45,RTDIR|LTDIR,        0,0, // twg dash
  59.      60,RTDIR,            0,0, // twg left arrow
  60.      62,LTDIR,            0,0, // twg right arrow
  61.      86,UPDIR,            0,0, // twg down arrow
  62.      94,DNDIR,            0,0, // twg up arrow
  63.     124,UPDIR|DNDIR,        0,0, // twg bar
  64.     179,UPDIR|DNDIR,        0,1, // bar
  65.     180,UPDIR|LTDIR|DNDIR,        1,1, // left fork
  66.     181,UPDIR|LTDIR|DNDIR,        2,1, // left fork
  67.     182,UPDIR|LTDIR|DNDIR,        1,2, // left fork
  68.     183,LTDIR|DNDIR,        1,2, // right up corner
  69.     184,LTDIR|DNDIR,        2,1, // right up corner
  70.     185,UPDIR|LTDIR|DNDIR,        2,2, // left fork
  71.     186,UPDIR|DNDIR,        0,2, // bar
  72.     187,LTDIR|DNDIR,        2,2, // right up  corner
  73.     188,UPDIR|LTDIR,        2,2, // right down corner
  74.     189,UPDIR|LTDIR,        1,2, // right down corner
  75.     190,UPDIR|LTDIR,        2,1, // right down corner
  76.     191,LTDIR|DNDIR,        1,1, // right up corner
  77.     192,RTDIR|UPDIR,        1,1, // left down corner
  78.     193,RTDIR|UPDIR|LTDIR,        1,1, // up fork
  79.     194,RTDIR|LTDIR|DNDIR,        1,1, // down fork
  80.     195,RTDIR|UPDIR|DNDIR,        1,1, // right fork
  81.     196,RTDIR|LTDIR,        1,0, // dash
  82.     197,RTDIR|UPDIR|LTDIR|DNDIR,1,1, // cross
  83.     198,RTDIR|UPDIR|DNDIR,        2,1, // right fork
  84.     199,RTDIR|UPDIR|DNDIR,        1,2, // right fork
  85.     200,RTDIR|UPDIR,        2,2, // left down corner
  86.     201,RTDIR|DNDIR,        2,2, // left up corner
  87.     202,RTDIR|UPDIR|LTDIR,        2,2, // up fork
  88.     203,RTDIR|LTDIR|DNDIR,        2,2, // down fork
  89.     204,RTDIR|UPDIR|DNDIR,        2,2, // right fork
  90.     205,RTDIR|LTDIR,        2,0, // dash
  91.     206,RTDIR|UPDIR|LTDIR|DNDIR,2,2, // cross
  92.     207,RTDIR|UPDIR|LTDIR,        2,1, // up fork
  93.     208,RTDIR|UPDIR|LTDIR,        1,2, // up fork
  94.     209,RTDIR|LTDIR|DNDIR,        2,1, // down fork
  95.     210,RTDIR|LTDIR|DNDIR,        1,2, // down fork
  96.     211,RTDIR|UPDIR,        1,2, // left down corner
  97.     212,RTDIR|UPDIR,        2,1, // left down corner
  98.     213,RTDIR|DNDIR,        2,1, // left up corner
  99.     214,RTDIR|DNDIR,        1,2, // left up corner
  100.     215,RTDIR|UPDIR|LTDIR|DNDIR,1,2, // cross
  101.     216,RTDIR|UPDIR|LTDIR|DNDIR,2,1, // cross
  102.     217,UPDIR|LTDIR,        1,1, // right down corner
  103.     218,RTDIR|DNDIR,        1,1, // left up corner
  104.     219,RTDIR|UPDIR|LTDIR|DNDIR,3,3, // full
  105.     // stream terminator
  106.       0,NODIR,            0,0
  107. };
  108.  
  109. // default alphabet initialized by system
  110. computer_alphabet *alph=
  111.  new computer_alphabet("ASCII_PC",256,ascii_pc_data);
  112.  
  113. computer_alphabet :: computer_alphabet(char *alphname, int bufsize, int *data)
  114. {
  115.     name=new char[strlen(alphname)+1];
  116.     strcpy(name,alphname);
  117.     numchars=bufsize;
  118.     grafc=new int[bufsize*2];
  119.     for (int *c=grafc+(numchars-1)*2; ; c--)
  120.         { *c=0; if (c==grafc) break; }
  121.     for (c=&(index[15][15]); ; c--)
  122.         { *c=0; if (c==&index[0][0]) break; }
  123.     if (!data) return;
  124.     for (; *data; data+=4)
  125.         poke_c((char)*data,intersection(*(data+1)),
  126.          weight_d(*(data+2),*(data+3)));
  127. }
  128.  
  129. computer_alphabet :: ~computer_alphabet(void)
  130.       { delete grafc; delete name; }
  131.  
  132. void computer_alphabet :: poke_c(char c, const intersection &avdir,
  133.  const weight_d &wgt)
  134. { // poke attributes in character table and index
  135.  
  136.     int cnum=(unsigned char)c;
  137.     if (cnum<1 || cnum>=numchars) return;    // caller's bug
  138.     *(grafc+cnum*2)=avdir();
  139.     *(grafc+cnum*2+1)=wgt();
  140.     index[wgt()][avdir()]=(avdir() ? cnum : 0);// the latter is caller's bug
  141. }
  142.  
  143. char computer_alphabet :: get_c(const intersection &avdir, weight_d wgt)
  144. { // retrive character by attributes, or a close match
  145.  
  146.     // fix caller's neglect - over-weight
  147.     if (wgt.y() && !(avdir.intersects(hdirs)))
  148.         wgt.replace(axis(HDIM),0);
  149.     if (wgt.x() && !(avdir.intersects(vdirs)))
  150.         wgt.replace(axis(VDIM),0);
  151.     if (!(wgt()) && !(avdir()))
  152.         return(' ');            // not semigraphic
  153.     // fix caller's neglect - under-weight
  154.     if (!(wgt.y()) && avdir.intersects(hdirs))
  155.         wgt.replace(axis(HDIM),
  156.             wgt.x());
  157.     if ((!wgt.x()) && avdir.intersects(vdirs))
  158.         wgt.replace(axis(VDIM),wgt.y());
  159.     int c;
  160.     // 1. exact match
  161.     if ((c=index[wgt()][avdir()])!=0)
  162.         return (char)c;
  163.     // 2. default full width
  164.     if ((c=index[(weight_d((wgt.y()? 3:0),(wgt.x()? 3:0)))()]
  165.      [avdir()])!=0)
  166.         return (char)c;
  167.     // 3. typewriter graphic - search for cross
  168.     if (!wgt() && ((c=index[0][alldirs()])!=0))
  169.             return (char)c;
  170.     // 4. full weight - search for cross
  171.     if ((wgt.y()==3 || wgt.x()==3) && ((c=index[fullwgt()][alldirs()])!=0))
  172.             return (char)c;
  173.     // 5. close match (nearest intersection in same weight group)
  174.     for (int i=avdir()-1; i; i--)
  175.         if ((c=index[wgt()][i])!=0)
  176.             return (char)c;
  177.     // 6. not found
  178.     return(' ');
  179. }
  180.  
  181. char computer_alphabet :: translate(char src, weight_d wgt)
  182. { // translate character to target width, as close as possible
  183.  
  184.     char tgt;
  185.     if ((tgt=get_c(intersection(cdir(src)),wgt))!=0)
  186.         return tgt;
  187.     return src;
  188. }
  189.  
  190. void computer_alphabet :: inverse(const axis &dim)
  191. { // invert the whole alphabet (e.g. latin=>semitic)
  192.  
  193.     for (int i=1; i<numchars-1; i++) {
  194.         intersection avdir=(cdir((char)i)), newdir((int)NODIR);
  195.         if (!avdir()) continue;
  196.         for (direction dir; dir(); dir++)
  197.             if (avdir>=dir)
  198.                 if (axis(dir)==dim) newdir+=(~dir);
  199.                 else newdir+=dir;
  200.         poke_c( (char)i,newdir(),cweight((char)i) );
  201.     }
  202. }
  203.  
  204. int computer_alphabet :: list(FILE *outf)
  205. { // print the index (originally intended for debugging)
  206.  
  207.     if (!outf) return;
  208.     int typeface[16], num_faces=0, num_semi=0;
  209.     for (int i=0; i<=15; i++) {
  210.         typeface[i]=0;
  211.         for (int j=0; j<=15; j++)
  212.             if (index[i][j])
  213.                 { typeface[i]=TRUE; num_semi++; }
  214.         if (typeface[i]) num_faces++;
  215.     }
  216.     fprintf(outf,"The %s Alphabet - semigrpahic cross-reference\n",name);
  217.     if (!num_faces)
  218.         { fprintf(outf,"(null)\n"); return; }
  219.     fprintf (outf,"contains %d semigraphic characters in %d weight groups\n",
  220.      num_semi,num_faces);
  221.     for (int w=0; w<=15; w++) {
  222.         if (!typeface[w]) continue;
  223.         fprintf(outf,"\n");
  224.         fprintf(outf,"WEIGHT GROUP code %d (h:v weight distribution ",w);
  225.         if ((weight_d(w)).y()>2) fprintf(outf,"full:");
  226.         else fprintf(outf,"%d:",(weight_d(w)).y());
  227.         if ((weight_d(w)).x()>2) fprintf(outf,"full)");
  228.         else fprintf(outf,"%d)",(weight_d(w)).x());
  229.         fprintf(outf,"\n");
  230.         for (int d=1; d<=15; d++)
  231.             if (index[w][d])
  232.                 fprintf(outf," %3d: %c function: %-8s (connects: %s)\n",index[w][d],
  233.                  (char)index[w][d],(intersection(d)).name(),
  234.                  (intersection(d)).names());
  235.     }
  236.     return i;
  237. }
  238.  
  239. /*********************** character connectivity ******************************/
  240.  
  241. boolean computer_alphabet :: ccont(char cfrm, char cto, const direction &curdir)
  242. { /* test if two semigraphics connect, given current direction */
  243.  
  244.     if (!(curdir())) return(FALSE);
  245.     if (!(intersection(cdir(cfrm))>=curdir))
  246.         return(FALSE); /* caller's bug */
  247.     /* target char must point at opposite direction */
  248.     if (intersection(cdir(cto))>=(~curdir)) {
  249.         axis curdim(curdir);
  250.         int widfrm=(cweight(cfrm)).width(curdim);
  251.         int widto=(cweight(cto)).width(curdim);
  252.         if (widfrm==widto        // same width
  253.         || widto==3 || widfrm==3)    // default terminal symbol
  254.         return(TRUE);
  255.     }
  256.     return(FALSE);
  257. }
  258.  
  259. char computer_alphabet :: carrw(char *env, direction ind, weight_d wgt,
  260.  int len, int pos, boolean directed)
  261. { // draw one character within an arc, context sensitive
  262.  
  263.     if (pos>len) pos=len;        // caller's bug
  264.     // adjust other axis to merge with char to be overlayed
  265.     wgt.replace(~(axis(ind)),(alph->cweight(*env)).width(~(axis(ind))));
  266.     if (pos==len)            // end of arc ?
  267.         if (len>1 || directed) {// invert connectivity
  268.             ind.opposite();
  269.             if (directed)    // arrowhead requested
  270.                 return get_c(intersection(ind()),wgt);
  271.         } // otherwise (not directed) - allow to "weld"
  272.     intersection avdir(cdir(*env)); avdir+=ind;
  273.     if (pos!=1 && pos!=len || avdir.unary())
  274.         avdir+=(~ind);            // opposite added by default
  275.     char c=get_c(avdir,wgt);        // init result
  276.     for (direction dir; dir(); dir++) {
  277.         if (dir!=ind && dir!=(~ind))    // vertical
  278.             if (*(env+dir.serial())!=' '
  279.             && ccont(c,*(env+dir.serial()),dir)) {
  280.                 if (!(avdir>=dir))
  281.                     { avdir+=dir; c=get_c(avdir,wgt); }
  282.             } else if (avdir>=dir)
  283.                 { avdir-=dir; c=get_c(avdir,wgt); }
  284.     }
  285.     if (pos<len && avdir.unary()) { // arrowhead not allowed in middle
  286.         avdir+=~(direction(avdir()));
  287.         c=get_c(avdir,wgt);
  288.     }
  289.     return c;
  290. }
  291.  
  292. char * computer_alphabet :: cearrw(char *env, direction ind, weight_d wgt,
  293.  int len, int pos, boolean directed)
  294. { // draw one character within an arc, possibly modifying neighbours
  295.  
  296.     if (pos>len) pos=len;        // caller's bug
  297.     // adjust other axis to merge with char to be overlayed
  298.     wgt.replace(~(axis(ind)),(alph->cweight(*env)).width(~(axis(ind))));
  299.     if (pos==len)            // end of arc ?
  300.         if (len>1 || directed) {// invert connectivity
  301.             ind.opposite();
  302.             if (directed) { // arrowhead requested
  303.                 *env=get_c(intersection(ind()),wgt);
  304.                 return(env);
  305.             }
  306.         } // else (not directed) - allow to "weld"
  307.     intersection avdir(cdir(*env)); avdir+=ind;
  308.     if (pos!=1 && pos!=len || avdir.unary())
  309.         avdir+=(~ind);            // opposite added by default
  310.     char c=get_c(avdir,wgt);        // init result
  311.     for (direction dir; dir(); dir++) {
  312.         char *ngbr=env+dir.serial();
  313.         if (dir!=ind && dir!=(~ind)) {    // vertical
  314.             if (*ngbr!=' ' && ccont(c,*ngbr,dir)) {
  315.                 if (!(avdir>=dir))
  316.                     { avdir+=dir; c=get_c(avdir,wgt); }
  317.             } else if (avdir>=dir)
  318.                 { avdir-=dir; c=get_c(avdir,wgt); }
  319.             // normalize weight
  320.             if ((alph->cdir(*env)).unary()) {
  321.                 if (ccont(*env,*ngbr,dir)) {
  322.                     wgt.replace(axis(dir),(alph->cweight(*ngbr)).width(axis(dir)));
  323.                     c=get_c(avdir,wgt);
  324.                 }
  325.             }
  326.         }
  327.         if (*ngbr!=' ' && !(avdir>=dir)) // trim neighbour
  328.             if (cdir(*ngbr)>=~dir && (cdir(*ngbr)).type()>=J_FORK)
  329.                 *ngbr=ctrim(*ngbr,~dir);
  330.     }
  331.     if (pos<len && avdir.unary()) { // arrowhead not allowed in middle
  332.         avdir+=~(direction(avdir()));
  333.         c=get_c(avdir,wgt);
  334.     }
  335.     *env=c;
  336.     return env;
  337. }
  338.  
  339. char computer_alphabet :: ctrim(char c, const direction &dir)
  340. { // trim char in protruding direction, if present
  341.  
  342.     intersection avdir(cdir(c));
  343.     if (!(avdir>=dir)) return(c); // not there
  344.     avdir-=dir;
  345.     return get_c(avdir,cweight(c));
  346. }
  347.  
  348. char computer_alphabet :: celong(char c, const direction &dir)
  349. { // elongate char in missing direction, if not already present
  350.  
  351.     intersection avdir(cdir(c));
  352.     if (avdir>=dir) return(c); // already there
  353.     avdir+=dir;
  354.     return get_c(avdir,cweight(c));
  355. }
  356.