home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_08_01 / 8n01070a < prev    next >
Text File  |  1990-02-19  |  13KB  |  633 lines

  1.  
  2.  
  3.  
  4. *****Listing 1*****
  5.  
  6. /*
  7.  * this is a very simple drawing program that 
  8.  * illustrates how to build a DCUWCU application
  9.  *
  10.  * Copyright 1989 Mark A. Johnson 
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <graphics.h>
  15.  
  16. #define M_POINTER    0    /* mouse shapes */
  17. #define M_CROSS        1
  18.  
  19. #define ON        1
  20. #define OFF        0
  21.  
  22. #define MAX_OBJECT    100
  23. #define ESC    27
  24.  
  25. #define BOX    'b'    /* object types we support */
  26. #define ELLIPSE    'e'
  27. #define LINE    'l'
  28. #define TEXT    't'
  29.  
  30. #define M_MAIN    1    /* handles for the menus */
  31. #define M_FILE    2
  32. #define M_OBJ    3
  33. #define M_ACT    4
  34.  
  35. #define A_COPY    1    /* action requests for button() */
  36. #define A_MOVE    2
  37. #define A_EDIT    3
  38.  
  39. #define min(a,b) ((a) < (b) ? (a) : (b))
  40. #define max(a,b) ((a) > (b) ? (a) : (b))
  41.  
  42. typedef struct { int type, l, t, r, b; char select, *data; } Object;
  43.  
  44. Object objects[MAX_OBJECT];    /* the table of objects defined so far */
  45. int last_object;        /* the end of the object table    */
  46.  
  47. int map[] = {             /* maps a M_OBJ menu item to an object */
  48.     0, BOX, ELLIPSE, LINE, TEXT };
  49.  
  50. char *about =             /* form used on the M_MAIN About item */
  51.     "  Draw This!|     by|Mark A. Johnson|  %{continue}";
  52.  
  53. char *help =             /* help message for wrong keyboard input */
  54.  "quit refresh : box line ellipse text : delete copy move edit";
  55.  
  56. char filename[20];        /* save the filename we're working with */
  57. char text[100];            /* extra buffer for text i/o */
  58.  
  59. int actn_obj = 0;        /* flag for button(), some action req */
  60. int make_obj = 0;        /* flag for button(), need to create */
  61. int slct_cnt = 0;        /* count of selected objects */
  62. int first;            /* helps make_object collect points */
  63. int grid = 0;            /* grid displayed, snap coords */
  64.  
  65. extern int Maxx, Maxy, MaxColor;
  66.  
  67. /* start routine, called by the application driver, gets things going */
  68.  
  69. start(argc, argv) char **argv; {
  70.     add_menu(M_MAIN, "Main:About|Quit|Refresh|Grid");
  71.     add_menu(M_FILE, "File:Read|Write|Save|Print");
  72.     add_menu(M_OBJ, "Objects:Box|Ellipse|Line|Text");
  73.     add_menu(M_ACT, "Actions:Delete|Copy|Move|Edit");
  74.     menu_state(M_ACT, 0);
  75.     if (argc > 1) {
  76.         strcpy(filename, argv[1]);
  77.         read_objects();
  78.     }
  79. }
  80.  
  81. /* no timers in this application , but DCUWCU needs an entry anyway */
  82.  
  83. timer() {}
  84.  
  85. /* button routine called every time button 1 is depressed */
  86.  
  87. button(b, x, y) {
  88.     if (make_obj) { /* need points to make an object */
  89.         make_object(x, y);
  90.     }
  91.     else if (actn_obj) { /* got a point for a copy or move */
  92.         action_object(x, y);
  93.     }
  94.     else    { /* do a selection */
  95.         select_object(in_object(x, y));
  96.     }
  97.     check_menu();
  98. }
  99.  
  100. /* menu routine called every time a menu item is selected */
  101.  
  102. menu(m, i) {
  103.     char junk = 0, on;
  104.     switch (m) {
  105.     case M_MAIN: /* main menu */
  106.         switch (i) {
  107.             case 1: form(about, &junk); break;
  108.             case 2: quit(); break;
  109.             case 3: refresh(); break;
  110.             case 4: do_grid(); break;
  111.         }
  112.         break;
  113.     case M_FILE: /* file menu */
  114.         if (i < 3 && !get_name())
  115.             break;
  116.         switch (i) {
  117.             case 1: read_objects(); break;
  118.             case 2: case 3: write_objects(); break;
  119.             case 4: print(); break;
  120.         }
  121.         break;
  122.     case M_OBJ: /* objects */
  123.         start_make(map[i]);
  124.         break;
  125.     case M_ACT: /* actions */
  126.         switch (i) {
  127.             case 1: kill_object(); break;
  128.             case 2: start_actn(A_COPY); break;
  129.             case 3: start_actn(A_MOVE); break;
  130.             case 4: start_edit(); break;
  131.         }
  132.         break;
  133.     }
  134. }
  135.  
  136. /* routine called everytime a key is struck */
  137.  
  138. keyboard(c) {
  139.     switch (c) {
  140.         case 'p': print(); break;
  141.         case 'g': do_grid(); break;
  142.         case 'r': refresh(); break;
  143.         case 'q': quit(); break;
  144.         case 'b': start_make(BOX); break;
  145.         case 't': start_make(TEXT); break;
  146.         case 'l': start_make(LINE); break;
  147.         case 'm': start_actn(A_MOVE); break;
  148.         case 'c': start_actn(A_COPY); break;
  149.         case 'd': kill_object(); break;
  150.         case 'e':
  151.             if (slct_cnt)
  152.                 start_edit();
  153.             else    start_make(ELLIPSE);
  154.             break;
  155.         default: msg(help);
  156.     }
  157. }
  158.  
  159. /* time to go, see if they really want to */
  160.  
  161. quit() {
  162.     char yes = 0, no = 0;
  163.     char *f_exit = "Are you sure?| %{yes} %{no}";
  164.     if (form(f_exit, &yes, &no) && no == 0)
  165.         finish();
  166. }
  167.  
  168. /*
  169.  * miscellaneous support routines
  170.  */
  171.  
  172. /* reset the current grid size */
  173.  
  174. do_grid() {
  175.     char gridval, ok = 0, nok = 0, x;
  176.     switch (grid) {
  177.         case 8: gridval = 1; break;
  178.         case 16: gridval = 2; break;
  179.         default: gridval = 0; break;
  180.     }
  181.     x = form("Change Grid Size|  %[none:8:16]| %{ok} %{cancel}",
  182.         &gridval, &ok, &nok);
  183.     if (x == 0 || nok) return;
  184.     grid = gridval * 8;
  185.     refresh(); 
  186. }
  187.  
  188. /* print the current screen somewhere, Epson-compatible graphics mode */ 
  189.  
  190. print() {
  191.     static char grhd[] = { ESC, 'L', 0, 0 }; /* 960 bit graphics */
  192.     static char grlf[] = { ESC, 'J', 24, '\r' }; /* line feed */
  193.     static char prbuf[960];
  194.     int x, y, i, b, n, any, pixel, max;
  195.     max = min(Maxx, 960);
  196.     grhd[2] = max;
  197.     grhd[3] = max >> 8;
  198.     mouse_state(OFF);
  199.     b = 0x80;
  200.     any = 0;
  201.     for (y = 0; y < Maxy; y++) {
  202.         for (x = 0; x < max; x++) {
  203.             if (getpixel(x, y)) {
  204.                 any = 1;
  205.                 prbuf[x] |= b;
  206.             }
  207.         }
  208.         b >>= 1;
  209.         if (b == 0) { /* out it goes */
  210.             if (any) {
  211.                 prn(grhd, 4);
  212.                 prn(prbuf, max);
  213.             }
  214.             prn(grlf, 4);
  215.             b = 0x80;
  216.             any = 0;
  217.             for (x = 0; x < max; x++)
  218.                 prbuf[x] = 0;
  219.         }
  220.     }
  221.     mouse_state(ON);
  222. }
  223.  
  224. /* print the n bytes out the printer port */
  225.  
  226. prn(s, n) char *s; { while (n--) biosprint(0, *s++, 0); }
  227.  
  228. /* select or de-select an object */
  229.  
  230. select_object(obj) {
  231.     int i;
  232.     Object *o;
  233.     if (obj == -1) { /* de-select all */
  234.         for (i = 0; i < last_object; i++) {
  235.             o = &objects[i];
  236.             if (o->select) {
  237.                 o->select = 0;
  238.                 highlight(o, 0);
  239.             }
  240.         }
  241.         slct_cnt = 0;
  242.     }
  243.     else    {
  244.         o = &objects[obj];
  245.         o->select = !o->select;
  246.         highlight(o, o->select);
  247.         slct_cnt += o->select ? 1 : -1;
  248.     }
  249. }
  250.  
  251. /* get a filename from the user, return 0 if abort */
  252.  
  253. get_name() {
  254.     return form("Path: %20s", filename);
  255. }
  256.  
  257. /* based on current select state, set the top-most menu */
  258.  
  259. check_menu() {
  260.     menu_state(M_ACT, slct_cnt > 0);
  261.     menu_state(M_OBJ, slct_cnt <= 0);
  262. }
  263.  
  264. /* start to make an object by collecting points */
  265.  
  266. start_make(type) {
  267.     char *s;
  268.     switch (make_obj = type) {
  269.         case BOX: s = "box: top left corner..."; break;
  270.         case ELLIPSE: s = "ellipse: top left corner..."; break;
  271.         case LINE: s = "line: one end..."; break;
  272.         case TEXT: s = "text: starting..."; break;
  273.     }
  274.     msg(s);
  275.     mouse_shape(M_CROSS);
  276.     first = 1;
  277. }
  278.  
  279. /* if enough points have been collected, make the object */
  280.  
  281. make_object(x, y) {
  282.     static int fx, fy;
  283.  
  284.     if (grid) snap(&x, &y);
  285.  
  286.     switch (make_obj) {
  287.     case TEXT:
  288.         *text = 0;
  289.         form("text: %20s", text);
  290.         add_object(TEXT, x, y, x + strlen(text)*8, y+8, text);
  291.         make_obj = 0;
  292.         mouse_shape(M_POINTER);
  293.         msg("");
  294.         break;
  295.     default:
  296.         if (first) {
  297.             fx = x;
  298.             fy = y;
  299.             first = 0;
  300.             line(x-3, y, x+3, y);
  301.             line(x, y-3, x, y+3);
  302.             if (make_obj == LINE)
  303.                 msg("other end...");
  304.             else    msg("bottom right corner...");
  305.         }
  306.         else    {
  307.             add_object(make_obj, fx, fy, x, y, 0L);
  308.             msg("");
  309.             make_obj = 0;
  310.             mouse_shape(M_POINTER);
  311.         }
  312.     }
  313. }
  314.  
  315. /* snap the coordinates to the nearest grid point */
  316.  
  317. snap(xp, yp) int *xp, *yp; {
  318.     int g2 = grid/2, g4 = grid/4, x = *xp, y = *yp;
  319.     x = ((x + g2) / grid) * grid;
  320.     y = ((y + g4) / g2) * g2;
  321.     msg("x %d->%d  y %d->%d", *xp, x, *yp, y);
  322.     *xp = x;
  323.     *yp = y;
  324. }
  325.  
  326. /* move, copy, or edit a figure */
  327.  
  328. action_object(x, y) {
  329.     int i, dx, dy;
  330.     Object *o;
  331.  
  332.     if (grid) snap(&x, &y);
  333.  
  334.     /* find reference point and compute distance moved */
  335.     dx = dy = (actn_obj == A_EDIT ? 0 : 10000);
  336.     for (i = 0; i < last_object; i++) {
  337.         o = &objects[i];
  338.         if (o->select) {
  339.             if (actn_obj == A_EDIT) {
  340.                 dx = max(o->r, dx);
  341.                 dy = max(o->b, dy);
  342.             }
  343.             else    {
  344.                 dx = min(o->l, dx);
  345.                 dy = min(o->t, dy);
  346.             }
  347.         }
  348.     }
  349.     dx = x - dx;
  350.     dy = y - dy;
  351.  
  352.     /* do it to all selected items, de-selecting as you go */
  353.     for (i = 0; i < last_object; i++) {
  354.         o = &objects[i];
  355.         if (o->select) {
  356.             o->select = 0;
  357.             highlight(o, 0);
  358.             switch (actn_obj) {
  359.             case A_COPY:
  360.                 highlight(o, 0);
  361.                 add_object(o->type,
  362.                     o->l + dx, o->t + dy,
  363.                     o->r + dx, o->b + dy,
  364.                     o->data);
  365.                 break;
  366.             case A_MOVE:
  367.                 draw_object(o, 0);
  368.                 o->l += dx;
  369.                 o->t += dy;
  370.                 o->r += dx;
  371.                 o->b += dy;
  372.                 draw_object(o, 1);
  373.                 break;
  374.             case A_EDIT:
  375.                 draw_object(o, 0);
  376.                 set_coords(o, 
  377.                     o->l, o->t, 
  378.                     o->r + dx, o->b + dy);
  379.                 draw_object(o, 1);
  380.                 break;
  381.             }
  382.         }
  383.     }
  384.  
  385.     /* deselect all and reset the mouse */
  386.     actn_obj = 0;
  387.     slct_cnt = 0;
  388.     mouse_shape(M_POINTER);
  389.     msg("");
  390.     check_menu();
  391. }
  392.  
  393. /* read objects from a file */
  394.  
  395. read_objects() {
  396.     int type, t, l, r, b;
  397.     FILE *f = fopen(filename, "r");
  398.     if (f != NULL) {
  399.         last_object = 0;
  400.         while (fgets(text, 100, f)) {
  401.             sscanf(text, "%c %d %d %d %d '%[^']\n", 
  402.                 &type, &l, &t, &r, &b, text);
  403.             add_object(type, l, t, r, b, text);
  404.         }
  405.         fclose(f);
  406.         msg("%d objects loaded", last_object);
  407.     }
  408.     else    msg("can't open '%s'", filename);
  409. }
  410.  
  411. /* write objects to a file */
  412.  
  413. write_objects() {
  414.     int i;
  415.     Object *o;
  416.     FILE *f;
  417.     if (*filename == 0 && !get_name())
  418.         return;
  419.     if ((f = fopen(filename, "w")) != NULL) {
  420.         for (i = 0; i < last_object; i++) {
  421.             o = &objects[i];
  422.             fprintf(f, "%c %d %d %d %d '%s'\n",
  423.                 o->type, o->l, o->t, o->r, o->b, 
  424.                 o->type == TEXT ? o->data : "");
  425.         }
  426.         fclose(f);
  427.     }
  428.     else    msg("can't write '%s'", filename);
  429. }
  430.  
  431. /* save the given string in malloc'ed memory */
  432.  
  433. char *
  434. strsave(s) char *s; {
  435.     char *malloc();
  436.     char *r = malloc(strlen(s)+1);
  437.     if (r) strcpy(r, s);
  438.     else msg("out of memory!!!");
  439.     return r;
  440. }
  441.  
  442. /* re-display all the objects on the screen */
  443.  
  444. refresh() {
  445.     int i, x, y, gy;
  446.     Object *o;
  447.     clearviewport();
  448.     setcolor(MaxColor);
  449.     if (grid) {
  450.         gy = grid/2;
  451.         for (x = grid; x < Maxx; x += grid)
  452.         for (y = gy; y < Maxy; y += gy)
  453.             putpixel(x, y, 1);
  454.     }
  455.     for (i = 0; i < last_object; i++) {
  456.         o = &objects[i];
  457.         draw_object(o, 1);
  458.         if (o->select) highlight(o, 1);
  459.     }
  460. }
  461.  
  462. /* (de)highlight the current selected item */
  463.  
  464. highlight(o, color) Object *o; {
  465.     setcolor(color);
  466.     rectangle(o->l-2, o->t-2, o->l+2, o->t+2);
  467.     rectangle(o->r-2, o->b-2, o->r+2, o->b+2);
  468. }
  469.  
  470. /* give the user some feedback */
  471.  
  472. msg(fmt, a, b, c, d) char *fmt; {
  473.     static int lastback = 0;
  474.     setfillstyle(EMPTY_FILL, 0);
  475.     bar(0, 0, lastback, 8);
  476.     sprintf(text, fmt, a, b, c, d);
  477.     setcolor(MaxColor);
  478.     outtextxy(0, 0, text);
  479.     lastback = strlen(text) * 8;
  480. }
  481.  
  482. /* 
  483.  * object handling 
  484.  */
  485.  
  486. /* see if x,y are in an object, begin looking at start + 1 */
  487.  
  488. in_object(x, y) {
  489.     static int last = 0;
  490.     int l, r, t, b;
  491.     Object *o;
  492.     int i = last+1, n = last_object;
  493.     while (n--) {
  494.         if (i >= last_object) i = 0;
  495.         o = &objects[i];
  496.         l = min(o->l, o->r);
  497.         r = max(o->l, o->r);
  498.         t = min(o->t, o->b);
  499.         b = max(o->t, o->b);
  500.         if (x >= l && x <= r && y >= t && y <= b)
  501.             return (last = i);
  502.         i++;
  503.     }
  504.     return (last = -1);
  505. }
  506.  
  507. /* add an object to the object table */
  508.  
  509. add_object(type, l, t, r, b, data) char *data; {
  510.     Object *o = &objects[last_object++];
  511.     char *s;
  512.     o->type = type;
  513.     set_coords(o, l, t, r, b);
  514.     o->select = 0;
  515.     if (type == TEXT)
  516.         o->data = strsave(data);
  517.     draw_object(o, 1);
  518. }
  519.  
  520. /* set the coordinates properly */
  521.  
  522. set_coords(o, l, t, r, b) Object *o; {
  523.     if (o->type == LINE) { /* no fixup on these */
  524.         o->l = l; 
  525.         o->t = t; 
  526.         o->r = r; 
  527.         o->b = b;
  528.     }
  529.     else    {
  530.         o->l = min(l, r);
  531.         o->t = min(t, b);
  532.         o->r = max(l, r);
  533.         o->b = max(t, b);
  534.     }
  535. }
  536.  
  537. /* draw an object on the screen */
  538.  
  539. draw_object(o, color) Object *o; {
  540.     int x, y, xrad, yrad;
  541.     setcolor(color);
  542.     switch (o->type) {
  543.     case TEXT:
  544.         x = strlen(o->data) * 8;
  545.         setfillstyle(EMPTY_FILL, 0);
  546.         bar(o->l, o->t, o->l + x, o->t + 8);
  547.         outtextxy(o->l, o->t, o->data);
  548.         break;
  549.     case BOX:
  550.         rectangle(o->l, o->t, o->r, o->b);
  551.         break;
  552.     case LINE:
  553.         line(o->l, o->t, o->r, o->b);
  554.         break;
  555.     case ELLIPSE:
  556.         x = o->l + (o->r - o->l)/2;
  557.         y = o->t + (o->b - o->t)/2;
  558.         xrad = o->r - x;
  559.         yrad = o->b - y;
  560.         ellipse(x, y, 0, 360, xrad, yrad);
  561.         break;
  562.     }
  563. }
  564.  
  565. /* delete an object */
  566.  
  567. kill_object() {
  568.     int i, j;
  569.     Object *o;
  570.     for (i = j = 0; i < last_object; i++) {
  571.         o = &objects[i];
  572.         if (o->select) {
  573.             highlight(o, 0);        
  574.             draw_object(o, 0);
  575.             o->select = 0;
  576.         }
  577.         else    {
  578.             if (i > j)
  579.                 objects[j++] = objects[i];
  580.             else    j++;
  581.         }
  582.     }
  583.     last_object = j;
  584.     slct_cnt = 0;
  585.     check_menu();
  586. }
  587.  
  588. /* start an edit on the selected objects */
  589.  
  590. start_edit() {
  591.     int i;
  592.     Object *o;
  593.     /* edit the text objects now */
  594.     for (i = 0; i < last_object; i++) {
  595.         o =  &objects[i];
  596.         if (o->type == TEXT && o->select) {
  597.             o->select = 0;
  598.             highlight(o, 0);
  599.             draw_object(o, 0);
  600.             strcpy(text, o->data);
  601.             if (form("edit: %20s", text)) {
  602.                 free(o->data);
  603.                 o->data = strsave(text);
  604.                 o->r = o->l + strlen(text)*8;
  605.             }
  606.             draw_object(o, 1);
  607.             slct_cnt--;
  608.         }
  609.     }
  610.     if (slct_cnt > 0) { /* must be other stuff */
  611.         start_actn(A_EDIT);
  612.     }
  613.     check_menu();
  614. }
  615.  
  616. /* initiate an action on selected objects */
  617.  
  618. start_actn(actn) {
  619.     switch (actn) {
  620.     case A_COPY: 
  621.         msg("copy to..."); 
  622.         break;
  623.     case A_MOVE: 
  624.         msg("move to..."); 
  625.         break;
  626.     case A_EDIT:
  627.         msg("editing...");
  628.         break;
  629.     }
  630.     actn_obj = actn;
  631.     mouse_shape(M_CROSS);
  632. }
  633.