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

  1. //          ┌───────┐
  2. //    ─────────>│ AVNER │
  3. //    ─────────>│  BEN  │──────> Software Engineering Method
  4. //          └───────┘
  5. //    10 Dov-Hoz st. Tel-Aviv 63416 Israel tel. 972-3-221535
  6.  
  7. // The Screen NAVigator, ver 1.10 April 1990
  8. // Copyright (c) 1989 by Avner Ben
  9. // Snav is not, and never was, free software.
  10. // for conditions for use refer to file "copyrigh.txt"
  11.  
  12. // The Screen Navigator is an object-oriented device-independent
  13. // character-graphics driver package, written in the C++ language,
  14. // distributed in the form of C++ source code.
  15. // For further information refer to the documentation files.
  16.  
  17. // The user may not omit this text, from the beginning of the file, to
  18. // the line of asterisks below.
  19.  
  20. /***************************************************************************/
  21.  
  22. // package nucleus part 3 - source code.
  23. // This file defines the generic "panel" (formatted output medium),
  24. // and the generic "shape" (character-graphic element to be charted on
  25. // the former).
  26.  
  27. // History:
  28. // 25.10.89 avner ben coded.
  29. /////// snav v1.1
  30. // 22.1.90-11.4.90 avner ben:
  31. // * seperated specific  shapes to snav3  * C++ v2.0  upgrade * debugged  title
  32. // centering  in  enframe  *  added  class  square_pos    *  renamed  class point
  33. // point_pos *    developed class  point * renamed class curve stroke  * in class
  34. // curve, replaced offset with pendn toggle * moved iterator methods from curve
  35. // to shape  * added  last-curve pointer  to shape  * added "intelligent" curve
  36. // appending mechanism, resolving  redundant strokes *    added color to    panel *
  37. // moved some function from implementation screen driver * added to class panel
  38. // color and cursor processing * added struct color_ind *
  39.  
  40. // Site history (of this copy):
  41. // __.__.__ ____________ : __________________.
  42.  
  43. #ifndef SNAV2_C
  44. #define SNAV2_C
  45. #endif
  46.  
  47. #include <stdio.h>
  48. #include "snav2.hpp"
  49. #include "snav2.hpp"
  50. #include <stdio.h>
  51.  
  52. ///////////////////// window dimensions:
  53.  
  54. point_pos :: point_pos(int y, int x, const direction &dir)
  55. { ypos=y; xpos=x; chg_dir(dir,1); }
  56.  
  57. point_pos :: point_pos(const direction &dir, const point_pos &other)
  58. { ypos=other.ypos; xpos=other.xpos; chg_dir(dir,1); }
  59.  
  60. point_pos & point_pos :: operator+=(const point_pos &offset)
  61. // shift by user-specified offset
  62. { ypos+=offset.ypos; xpos+=offset.xpos; return(*this); }
  63.  
  64. point_pos & point_pos :: operator-=(const point_pos &shifted)
  65. // shift conter to user-specified offset
  66. { ypos-=shifted.ypos; xpos-=shifted.xpos; return(*this); }
  67.  
  68. void point_pos :: move(const direction &dir, int len)
  69. {
  70.     switch (dir()) {
  71.         case RTDIR :    xpos+=len; break;
  72.         case UPDIR :    ypos-=len; break;
  73.         case LTDIR :    xpos-=len; break;
  74.         case DNDIR :    ypos+=len; break;
  75.     }
  76. }
  77.  
  78. int point_pos :: how_far(const direction &dir)
  79. { // only positive result counts
  80.  
  81.     int result=0;
  82.     switch (dir()) {
  83.         case RTDIR :    if (xpos>0) result=xpos; break;
  84.         case UPDIR :    if (ypos<0) result=-ypos; break;
  85.         case LTDIR :    if (xpos<0) result=-xpos; break;
  86.         case DNDIR :    if (ypos>0) result=ypos; break;
  87.     }
  88.     return result;
  89. }
  90.  
  91. void point_pos :: chg_dir(const direction &dir, int len)
  92. {
  93.     switch (dir()) {
  94.         case RTDIR :    xofst=len; yofst=0; break;
  95.         case UPDIR :    xofst=0; yofst=-len; break;
  96.         case LTDIR :    xofst=-len; yofst=0; break;
  97.         case DNDIR :    xofst=0; yofst=len; break;
  98.     }
  99. }
  100.  
  101. char * point_pos :: name()
  102. {
  103.     static char result[12];
  104.     sprintf(result,"%-d:%-d",ypos,xpos);
  105.     return result;
  106. }
  107.  
  108. void square_pos :: move_limit(const direction &dir, int ofst)
  109. {
  110.     switch (dir()) {
  111.         case RTDIR :    bot.xpos+=ofst; break;
  112.         case UPDIR :    top.ypos-=ofst; break;
  113.         case LTDIR :    top.xpos-=ofst; break;
  114.         case DNDIR :    bot.ypos+=ofst; break;
  115.     }
  116. }
  117.  
  118. void square_pos :: set_limit(const direction &dir, int pos)
  119. { // modify window dimensions
  120.  
  121.     switch(dir()) {
  122.         case RTDIR :    bot.xpos=pos; break;
  123.         case UPDIR :    top.ypos=pos; break;
  124.         case LTDIR :    top.xpos=pos; break;
  125.         case DNDIR :    bot.ypos=pos; break;
  126.     }
  127. }
  128.  
  129. void square_pos :: set_start(const point_pos &start)
  130. {
  131.     top=start;
  132.     curlen=bot.ypos-top.ypos+1;
  133.     curwd=bot.xpos-top.xpos+1;
  134. }
  135.  
  136. void square_pos :: set_end(const point_pos &end)
  137. {
  138.     bot=end;
  139.     curlen=bot.ypos-top.ypos+1;
  140.     curwd=bot.xpos-top.xpos+1;
  141. }
  142.  
  143. void square_pos :: set_end_y(int len)
  144. {
  145.     bot.sety(top.ypos+len-1);
  146.     curlen=len;
  147. }
  148.  
  149. void square_pos :: set_end_x(int wd)
  150. {
  151.     bot.setx(top.xpos+wd-1);
  152.     curwd=wd;
  153. }
  154.  
  155. void square_pos :: move(const direction &dir, int len)
  156. {
  157.     top.move(dir,len); bot.move(dir,len);
  158. }
  159.  
  160. int square_pos :: len(const axis &dim)
  161. {
  162.     if (dim==vdim) return curlen; else return(curwd);
  163. }
  164.  
  165. char * square_pos :: name()
  166. {
  167.     static char result[24];
  168.     sprintf(result,"%sx%s",top.name(),bot.name());
  169.     return result;
  170. }
  171.  
  172. void color_ind :: toggle_attr(vd_attr at)
  173. { if (ask_attr(at)) attr_off(at); else attr_on(at); }
  174.  
  175. void color_ind :: set_for_clr(vd_clr color)
  176. { if (attr==VD_REV) backgnd=color; else forgnd=color; }
  177.  
  178. void color_ind :: set_back_clr(vd_clr color)
  179. { if (attr==VD_REV) forgnd=color; else backgnd=color; }
  180.  
  181. vd_clr color_ind :: ask_for_clr()
  182. { if (attr==VD_REV) return backgnd; else return forgnd; }
  183.  
  184. vd_clr color_ind :: ask_back_clr()
  185. { if (attr==VD_REV) return forgnd; else return backgnd; }
  186.  
  187. void color_ind :: normalize()
  188. {
  189.     if (attr==VD_REV) {
  190.         vd_clr t=forgnd;
  191.         forgnd=backgnd; backgnd=t;
  192.         attr_off(VD_REV);
  193.     }
  194. }
  195.  
  196. boolean color_ind :: operator()()
  197. { return attr && (int)backgnd && (int)forgnd; }
  198.  
  199. boolean color_ind :: operator==(const color_ind &other)
  200. { return (attr==other.attr && backgnd==other.backgnd && forgnd==other.forgnd); }
  201.  
  202. boolean color_ind :: operator!=(const color_ind &other)
  203. { return (attr!=other.attr || backgnd!=other.backgnd || forgnd!=other.forgnd); }
  204.  
  205. /////////////////////////// the generic panel
  206.  
  207. static point_pos top_pos(1,1), bot_pos(25,80);
  208.  
  209. panel :: panel(square_pos *window, color_ind *clr, direction *dir, boolean ingraph, boolean inwrap)
  210.  : win(top_pos,bot_pos)
  211. {
  212.     lang=0;
  213.     if (window) win=*window;
  214.     if (clr) color=def_color=*clr;
  215.     if (dir) curdir=*dir;                // default direction right
  216.     takes_graph=ingraph; wrap_around=inwrap;
  217.     fix();
  218. }
  219.  
  220. void panel :: fix(void)
  221. {
  222.     top=win.start();
  223.     bot=win.end();
  224.     hlen=bot.xpos-top.xpos+1;
  225.     vlen=bot.ypos-top.ypos+1;
  226. }
  227.  
  228. boolean panel :: ask_legal(point_pos *pt)
  229. {
  230.     return(
  231.         pt->xpos>=top.xpos
  232.          && pt->xpos<=bot.xpos
  233.          && pt->ypos>=top.ypos
  234.          && pt->ypos<=bot.ypos
  235.     );
  236. }
  237.  
  238. boolean panel :: next(direction *dir, point_pos *pt0)
  239. { // next cursor position, if movement possible. wrap-around not practiced
  240.  
  241.     if (!dir) dir=&curdir;
  242.     point_pos *pt=(pt0? pt0 : &cursor);
  243.     switch ((*dir)()) {
  244.         case RTDIR :    if (pt->xpos>=bot.xpos) return FALSE;
  245.                 pt->move(rt); break;
  246.         case UPDIR :    if (pt->ypos<=top.ypos) return FALSE;
  247.                 pt->move(up); break;
  248.         case LTDIR :    if (pt->xpos<=top.xpos) return FALSE;
  249.                 pt->move(lt); break;
  250.         case DNDIR :    if (pt->ypos>=bot.ypos) return FALSE;
  251.                 pt->move(dn); break;
  252.     }
  253.     if (!pt0) posit();
  254.     return TRUE;
  255. }
  256.  
  257. boolean panel :: wpnext(direction *dir, point_pos *pt0)
  258. { // next cursor position. wrap-around is practiced if allowed by panel's setup
  259. ///////////////// experimental code! //////////////////////////
  260.  
  261.     if (!dir) dir=&curdir;
  262.     point_pos *pt=(pt0? pt0 : &cursor);
  263.     connective dirval=(*dir)();
  264.     if (dirval==RTDIR) {
  265.         if (pt->xpos<bot.xpos) pt->move(rt);
  266.         else if (wrap_around) {
  267.             pt->xpos=top.xpos;
  268.             pt->move(dn);
  269.             if (pt->ypos>bot.ypos) pt->ypos=top.ypos;
  270.         } else return FALSE;
  271.     } else if (dirval==UPDIR) {
  272.         if (pt->ypos>top.ypos) pt->move(up);
  273.         else if (wrap_around) {
  274.             pt->ypos=bot.ypos;
  275.             pt->move(lt);
  276.             if (pt->xpos<top.xpos) pt->xpos=bot.xpos;
  277.         } else return FALSE;
  278.     } else if (dirval==LTDIR) {
  279.         if (pt->xpos>top.xpos) pt->move(lt);
  280.         else if (wrap_around) {
  281.             pt->setx(bot.xpos);
  282.             pt->move(dn);
  283.             if (pt->ypos>bot.ypos) pt->ypos=top.ypos;
  284.         } else return FALSE;
  285.     } else if (dirval==DNDIR) {
  286.         if (pt->ypos<bot.ypos) pt->move(dn);
  287.         else if (wrap_around) {
  288.             pt->ypos=top.ypos;
  289.             pt->move(rt);
  290.             if (pt->xpos>bot.xpos) pt->xpos=top.xpos;
  291.         } else return FALSE;
  292.     }
  293.     if (!pt0) posit();
  294.     return TRUE;
  295. }
  296.  
  297. char panel :: next_c(direction *dir, point_pos *pt0)
  298. { // get neighbour of cursor/specified char
  299.  
  300.     if (!dir) dir=&curdir;
  301.     point_pos pt; if (pt0) pt=*pt0; else pt=cursor;
  302.     if (!next(dir,&pt)) return ' ';       // no wrap-around
  303.     return get_c(&pt);
  304. }
  305.  
  306. char * panel :: env(point_pos *pt)
  307. { // returns string made of current char, followed by sorounding chars
  308.  
  309.     static char buf[6];
  310.     buf[0]=get_c(pt);
  311.     for (direction dir; dir(); dir++)
  312.         buf[dir.serial()]=next_c(&dir,pt);    // no wrap-around
  313.     buf[5]='\0';
  314.     return(buf);
  315. }
  316.  
  317. void panel :: home()
  318. {
  319.     switch (curdir()) {
  320.         case RTDIR :    // going right and down (normal latin)
  321.                 cursor.ypos=top.ypos;
  322.                 cursor.xpos=top.xpos;
  323.                 break;
  324. ///////////////// experimental code! //////////////////////////
  325.         case UPDIR :    // going up and left (whatever that means)
  326.                 cursor.ypos=bot.ypos;
  327.                 cursor.xpos=bot.xpos;
  328.                 break;
  329.         case LTDIR :    // going left and down (semitic languages)
  330.                 cursor.ypos=top.ypos;
  331.                 cursor.xpos=bot.xpos;
  332.                 break;
  333.         case DNDIR :    // going down and right (asian languages?)
  334.                 cursor.ypos=top.ypos;
  335.                 cursor.xpos=top.xpos;
  336.                 break;
  337.     }
  338.     posit();
  339. }
  340.  
  341. void panel :: clr_eol(point_pos *pt0)
  342. { // erase to end of line
  343.  
  344.     point_pos pt;
  345.     if (pt0) pt=*pt0; else pt=cursor;
  346.     if (!ask_legal(&pt)) return;
  347.     color_ind sav=color; reset_color();
  348.     for (; pt.xpos<=bot.xpos; pt.move(rt))
  349.         put_c(' ',&pt);
  350.     color=sav;
  351. }
  352.  
  353. void panel :: clear()
  354. { // clear whole screen and position home
  355.  
  356.     int maxy=bot.ypos;
  357.     reset_color();
  358.     point_pos pt(dn,top);
  359.     for (; pt.ypos<=maxy; pt++)
  360.         clr_eol(&pt);
  361.     home();
  362. }
  363.  
  364. void panel :: put_s(char *s, point_pos *pt0, direction *dir0)
  365. { // write a string on screen
  366.  
  367.     point_pos *pt=NULL; if (pt0) pt=new point_pos(*pt0);
  368.     direction *dir=NULL; if (dir0) dir=new direction(*dir0);
  369.     for (; *s; s++) {
  370.         put_c(*s,pt,dir);
  371.         // put_c advances panel->cursor (if pt==NULL). otherwise...
  372.         if (pt)
  373.             if (!next(dir,pt)) return; // no wrap-around!
  374.     }
  375.     if (pt) delete pt; if (dir) delete dir;
  376. }
  377.  
  378. int panel :: ask_limit(const direction &dir)
  379. { // beginning/end of window - height/breadth
  380.  
  381.     switch(dir()) {
  382.         case RTDIR :    return bot.xpos;
  383.         case UPDIR :    return top.ypos;
  384.         case LTDIR :    return top.xpos;
  385.         case DNDIR :    return bot.ypos;
  386.     }
  387.     return 0;
  388. }
  389.  
  390. void panel :: set_limit(const direction &dir, int pos)
  391. { // modify window dimensions
  392.  
  393.     win.set_limit(dir,pos);
  394.     fix();
  395. }
  396.  
  397. void panel :: move_limit(const direction &dir, int ofst)
  398. {
  399.     win.move_limit(dir,ofst);
  400.     fix();
  401. }
  402.  
  403. int panel :: ask_len(const axis &dim)
  404. {
  405.     if (dim==hdim) return hlen;
  406.     if (dim==vdim) return vlen;
  407.     return 0;
  408. }
  409.  
  410. point_pos panel :: ask_corner(const direction &dir)
  411. { // only top-left or bottom-right
  412.  
  413.     if (dir()==UPDIR || dir()==LTDIR)  return top;
  414.     return bot;
  415. }
  416.  
  417. void panel :: set_color(const color_ind &clr)
  418. { color=clr; fix(); }
  419.  
  420. void panel :: toggle_attr(vd_attr at)
  421. { color.toggle_attr(at); fix(); }
  422.  
  423. void panel :: set_def_attr(vd_attr at)
  424. {
  425.     def_color.toggle_attr(at);
  426.     set_color(def_color);
  427. }
  428.  
  429. void panel :: set_def_background(vd_clr colornum)
  430. {
  431.     def_color.backgnd=colornum;
  432.     set_color(def_color);
  433.     paint_background(colornum);
  434. }
  435.  
  436. void panel :: paint_background(vd_clr colornum)
  437. {
  438.     int maxy=bot.ypos, maxx=bot.xpos;
  439.     for (point_pos ypt(dn,top); ypt.ypos<=maxy; ypt++)
  440.         for (point_pos xpt(rt,ypt); xpt.xpos<=maxx; xpt++)
  441.             put_background(colornum,&xpt);
  442. }
  443.  
  444. void panel :: set_def_forground(vd_clr colornum)
  445. {
  446.     def_color.forgnd=colornum;
  447.     set_color(def_color);
  448. }
  449.  
  450. boolean panel :: enframe(const weight_d &wgt, char *intitle, boolean centered)
  451. { // enclose window in box, and contract
  452.  
  453.     if (hlen<3 || vlen<3) return FALSE;
  454.     (oblong(hlen,vlen,wgt)).list(this,&top);
  455.     if (*intitle) {
  456.         int len=(strlen(intitle)<=hlen-2 ?
  457.          strlen(intitle) : hlen-2);
  458.         char *s=new char[len+1];
  459.         for (int i=0; i<len; i++) s[i]=intitle[i];
  460.         s[len]='\0'; point_pos pt=top;
  461.         switch (curdir()) {
  462.             case RTDIR :    if (!centered) pt.move(rt);
  463.                     else pt.move(rt,(hlen-2-len)/2);
  464.                     put_s(s,&pt);
  465.                     break;
  466. ///////////////// experimental code! //////////////////////////
  467.             case UPDIR :    if (centered)
  468.                     put_s(s,&point_pos(vlen+1-(vlen-2-len)/2,
  469.                      bot.xpos));
  470.                     else put_s(s,&point_pos(bot.ypos-1,bot.xpos));
  471.                     break;
  472.             case LTDIR :    if (centered)
  473.                     put_s(s,&point_pos(top.ypos,hlen+1
  474.                      -(hlen-2-len)/2));
  475.                     else put_s(s,&point_pos(top.ypos,bot.xpos-1));
  476.                     break;
  477.             case DNDIR :    if (centered)
  478.                     put_s(s,&point_pos((vlen-2-len)/2,top.xpos));
  479.                     else put_s(s,&point_pos(top.ypos,top.xpos+1));
  480.                     break;
  481.         }
  482.         delete s;
  483.     }
  484.     // contract
  485.     move_limit(lt,-1);
  486.     move_limit(rt,-1);
  487.     move_limit(up,-1);
  488.     move_limit(dn,-1);
  489.     home();
  490.     return TRUE;
  491. }
  492.  
  493. void panel :: deframe()
  494. { // expand, checking nothing
  495.  
  496.     move_limit(lt);
  497.     move_limit(rt);
  498.     move_limit(up);
  499.     move_limit(dn);
  500.     (oblong(hlen,vlen)).clear(this,&top);
  501. }
  502.  
  503. boolean panel :: twg_c(point_pos *pt)
  504. { // translate typewriter graphic char to 1h1v semigraphic
  505.   // ("full screen" algorithm)
  506.  
  507.     char *around=env(pt); char c=*around;
  508.     intersection avdir=alph->cdir(c);
  509.     if (!avdir() || (alph->cweight(c))()) return FALSE; // not a twg char
  510.     // ajust to actual connectivity
  511.     intersection actdir=alph->cdir(c);
  512.     char csemi=alph->translate(c,h1v1);        // semigraphic self
  513.     char ctwg=alph->translate(csemi,twgwgt);         // semigraphic self
  514.     for (direction dir; dir(); dir++)
  515.         if (actdir>=dir
  516.          && !alph->ccont(ctwg,around[dir.serial()],dir) // connects as is?
  517.          && !alph->ccont(csemi,around[dir.serial()],dir)) // connects edited?
  518.                     actdir-=dir;     // no partner in direction
  519.     if (!actdir()) return FALSE;   // lonely char - no arc
  520.     if (actdir.unary()) {           // arc terminator
  521.         if (avdir.unary()) {   // arrow
  522.             if (ask_grph()) put_c(alph->translate(c,h1v1),pt);
  523.         } else {        // not arrow
  524.             // does arc continue from partner?
  525.             direction opsdir(actdir()); opsdir.opposite();
  526.             point_pos ngbr=*pt;
  527.             if (!next(&direction(actdir()),&ngbr)) return FALSE;
  528.             around=env(&ngbr); char c1=*around;
  529.             char c1semi=alph->translate(c1,h1v1);
  530.             char c1twg=alph->translate(c1semi,twgwgt);
  531.             intersection actdir1=alph->cdir(c1);
  532.             for (direction dir; dir(); dir++)
  533.                 if (actdir1>=dir && dir!=opsdir
  534.                  && (alph->ccont(c1twg,around[dir.serial()],dir)
  535.                  || alph->ccont(c1semi,
  536.                   around[dir.serial()],dir))) {
  537.                     if (avdir.type()==J_CROSS)
  538.                         csemi=alph->ctrim(csemi,opsdir);
  539.                     put_c(csemi,pt);
  540.                     return TRUE; // more than two in arc
  541.                 }
  542.             if ((alph->cdir(c1)).unary()) {   // other is arrow
  543.                 if (avdir.type()==J_CROSS)
  544.                     csemi=alph->ctrim(csemi,opsdir);
  545.                 put_c(csemi,pt);
  546.             }
  547.         }
  548.     } else put_c(alph->get_c(actdir,h1v1),pt); // middle of arc
  549.     return TRUE;
  550. }
  551.  
  552. int panel :: twg()
  553. { // translate typewriter graphics to 1h1v semigraphics
  554.  
  555.     int changes=0;
  556.     point_pos pt(rt,top);
  557.     for (; pt.ypos<=bot.ypos; pt.move(dn))
  558.         for (pt.setx(top.xpos); pt.xpos<=bot.xpos; pt++)
  559.             changes+=twg_c(&pt);
  560.     return changes;
  561. }
  562.  
  563. void panel :: arclist(point_pos *pt0, int len, const direction &dir,
  564.  const weight_d &wgt, boolean tipped, color_ind *color)
  565. { // draw straight line graphic primitive. interface for arc::list()
  566.  
  567.     point_pos pt(dir,*pt0);
  568.     color_ind savcolor=ask_color();
  569.     if (color) {                        // forground only!
  570.         color_ind newclr=ask_color();
  571.         newclr.set_for_clr(color->forgnd);
  572.         set_color(newclr);
  573.     }
  574.     for (int i=1; i<=len; ++i) {
  575. #ifndef ENV_MODIFY                     // draw current char only
  576.         put_c(alph->carrw(env(&pt),dir,wgt,len,i,tipped),&pt);
  577. #else                                // trim excess
  578.         char around[6]; strcpy(around,env(&pt));
  579.         alph->cearrw(around,dir,wgt,len,i,tipped);
  580.         put_c(*around,&pt);
  581.         for (direction tdir; tdir(); tdir++)
  582.             point_pos ngbr; color_ind tclr;
  583.             if (around[tdir.serial()]!=' ') {
  584.                 ngbr=pt;
  585.                 if (next(&tdir,&ngbr)) {
  586.                     tclr=get_color(&ngbr);
  587.                     put_c(around[tdir.serial()],&ngbr);
  588.                     put_color(tclr,&ngbr);
  589.                 }
  590.             }
  591. #endif
  592.         pt++;                    // legality of pos ignored
  593.     }
  594.     set_color(savcolor);
  595. }
  596.  
  597. void panel :: arcclr(point_pos *pt0, int len, const direction &dir)
  598. { // clear space formerly occupied by straight line
  599.  
  600.     point_pos pt(dir,*pt0);
  601.     color_ind savcolor=ask_color(); reset_color();
  602.     for (int i=1; i<=len; ++i) {
  603.         put_c(' ',&pt);
  604.         pt++;                    // legality of pos ignored
  605.     }
  606.     set_color(savcolor);
  607. }
  608.  
  609. intersection panel :: gowhere(point_pos *junction, intersection *result)
  610. { // directions of arcs available from specified point on screen
  611.  
  612.     if (!result) result=new intersection((int)NODIR);
  613.     else *result=intersection((int)NODIR);
  614.     char around[6]; strcpy(around,env(junction));
  615.     for (direction dir; dir(); dir++)
  616.         if (alph->ccont(*around,*(around+dir.serial()),dir))
  617.             *result+=dir;
  618.     return(*result);
  619. }
  620.  
  621. square_pos panel :: ask_window(void)
  622. { return win; }
  623.  
  624. panel :: ~panel(void)
  625. { restore(); }
  626.  
  627. color_ind panel :: ask_color(void)
  628. { return color; }
  629.  
  630. color_ind panel :: ask_def_color(void)
  631. { return def_color; }
  632.  
  633. boolean panel :: ask_attr(vd_attr at)
  634. { return color.ask_attr(at); }
  635.  
  636. void panel :: reset_color(void)
  637. { set_color(def_color); }
  638.  
  639. void panel :: set_def_color(const color_ind &clr)
  640. { def_color=clr; set_color(clr); set_def_background(clr.backgnd); }
  641.  
  642. boolean panel :: ask_grph(void)
  643. { return takes_graph; }
  644.  
  645. boolean panel :: ask_wrap(void)
  646. { return wrap_around; }
  647.  
  648. void panel :: set_dir(const direction &dir)
  649. { curdir=dir; }
  650.  
  651. void panel :: turn(void)
  652. { curdir.clockwise(); }
  653.  
  654. int panel :: ask_lang(void)
  655. { return lang; }
  656.  
  657. void panel :: set_lang(int inlang)
  658. { lang=inlang; }
  659.  
  660. ////////////////////////// screen type selection /////////////////////
  661.  
  662. screen_driver_manager :: screen_driver_manager(int def)
  663. { default_screen=def; }
  664.  
  665. int screen_driver_manager :: ask_default(void)
  666. { return default_screen; }
  667.  
  668. void screen_driver_manager :: set_default(int def)
  669. { default_screen=def; }
  670.  
  671. ////////////////////////// line-drawing primitives
  672.  
  673. void arc :: list(panel *scr, point_pos *pt)
  674. { scr->arclist(pt,len,dir,wgt,tipped,color); }
  675.  
  676. void arc :: clear(panel *scr, point_pos *pt)
  677. { scr->arcclr(pt,len,dir); }
  678.  
  679. void arc ::  contract(void)
  680. { if (len) len--; }
  681.  
  682. void arc ::  expand(void)
  683. { len++; }
  684.  
  685. void arc ::  turn(void)
  686. { dir.clockwise(); }
  687.  
  688. void arc ::  invert(void)
  689. { dir.opposite(); }
  690.  
  691. void arc ::  toggle_tip(void)
  692. { tipped=!tipped; }
  693.  
  694. void arc ::  set_len(int inlen)
  695. { len=inlen; }
  696.  
  697. void arc ::  set_dir(const direction &indir)
  698. { dir=indir; }
  699.  
  700. void arc ::  set_wgt(const weight_d &inwgt)
  701. { wgt=inwgt; }
  702.  
  703. void arc ::  mask(const weight_d &other_wgt)
  704. { wgt.mask(other_wgt); }
  705.  
  706. stroke :: stroke(arc *src, boolean pen_down) : arc(*src), offset(0,0)
  707. {
  708.     pendn=pen_down; color=NULL;
  709.     next=NULL;
  710. }
  711.  
  712. stroke :: stroke(int inlen, const direction &indir, const weight_d &inwgt,
  713.  boolean intip, color_ind *incolor, boolean pen_down) :
  714.  arc(inlen, indir, inwgt, intip, incolor), offset(1,1)
  715. {
  716.     pendn=pen_down;
  717.     if (incolor) {
  718.         color=new color_ind;
  719.         *color=*incolor;
  720.     } else *color=NULL;
  721.     next=NULL;
  722. }
  723.  
  724. void stroke :: toggle_pen()
  725. { pendn=!pendn; }
  726.  
  727. boolean stroke :: pen_is_down()
  728. { return pendn; }
  729.  
  730. ///////////////////////////// shape drawing ///////////////////////////////
  731.  
  732. shape :: shape(stroke *sk, char *inname)
  733. {
  734.     stsk=ensk=sk;
  735.     sname=new char[strlen(inname)+1]; strcpy(sname,inname);
  736. }
  737.  
  738. void shape :: append_stroke(stroke *sk)
  739. {
  740.     if (!sk) return;                       // caller's bug
  741.     stroke *lastsk=ensk;
  742.     if (!stsk) stsk=ensk=sk;
  743.     else if (sk->dir==ensk->dir && sk->wgt()==ensk->wgt()
  744.      && (sk->color == ensk->color || sk->color && ensk->color
  745.      && *(sk->color)==*(ensk->color)))     // redundant?
  746.         if (sk->len>1)
  747.             if (sk->pendn!=ensk->pendn)
  748.                 ensk=ensk->next=sk; // not redundant - accept!
  749.             else ensk->len+=sk->len;      // redundant - weld!
  750.         else;            // redundant arcs of length 1 are bugs
  751.     else ensk=ensk->next=sk;
  752.     if (sk!=ensk) { delete sk; return; }
  753.     // compute offset from base
  754.     if (lastsk) {
  755.         sk->offset=lastsk->offset;
  756.         (sk->offset).move(sk->dir,sk->len-1);
  757.     }
  758.     // fill-in axis_weight, when scan started in midline (tracing shape)
  759.     if (sk->wgt() && !((sk->wgt).y() && (sk->wgt).x()))
  760.         if (lastsk && lastsk->pen_is_down())
  761.             (sk->wgt).mask(lastsk->wgt);
  762.         else for (stroke *sk0=stsk; sk0; sk0=sk0->next)
  763.             if (sk0->offset==sk->offset)
  764.                 { (sk->wgt).mask(sk0->wgt); break; }
  765. }
  766.  
  767. void shape :: append_stroke(const point_pos &offset)
  768. {
  769.     for (direction dir; dir(); dir++)
  770.         if (offset.how_far(dir))
  771.             append_stroke(new stroke(offset.how_far(dir)+1,dir,twgwgt,FALSE,0,FALSE));
  772. }
  773.  
  774. shape :: ~shape()
  775. {
  776.     delete sname;
  777.     if (stsk) {
  778.         stroke *next=stsk->next;
  779.         for (; stsk; stsk=next) {
  780.             next=stsk->next;
  781.             delete stsk;
  782.         }
  783.     }
  784. }
  785.  
  786. void shape :: list(panel *scr, point_pos *pt0, boolean stay)
  787. { // the generic shape lister - used if inherited method not provided
  788.  
  789.     point_pos pt=*pt0;
  790.     for (stroke *sk=stsk; sk; sk=sk->next) {
  791.         if (sk->len && sk->dir()) {
  792.             if (sk->pendn)
  793.                 sk->arc::list(scr,&pt);
  794.             pt.move(sk->dir(),sk->len-1);
  795.         }
  796.     }
  797.     if (!stay) *pt0=pt;
  798. }
  799.  
  800. void shape :: clear(panel *scr, point_pos *pt0, boolean stay)
  801. { // the generic shape eraser - used if inherited method not provided
  802.  
  803.     point_pos pt=*pt0;
  804.     for (stroke *sk=stsk; sk; sk=sk->next) {
  805.         if (sk->len && sk->dir()) {
  806.             if (sk->pendn)
  807.                 sk->arc::clear(scr,&pt);
  808.             pt.move(sk->dir(),sk->len-1);
  809.         }
  810.     }
  811.     if (!stay) *pt0=pt;
  812. }
  813.  
  814.  
  815.