home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / IRIT / IRITS.ZIP / GRAPHGEN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  22.5 KB  |  713 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d polygonal solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. *   General routines to    handle the graphic calls.                 *
  7. * currently supported devices:                             *
  8. * Input: Keyboard, mouse.                             *
  9. * Output: Hercules, EGA/VGA.                             *
  10. *****************************************************************************/
  11.  
  12. #include <stdio.h>
  13. #include <conio.h>
  14. #include <string.h>
  15. #include <dir.h>
  16. #include <dos.h>
  17. #include <math.h>
  18. #include <ctype.h>
  19. #include <graphics.h>
  20. #include <stdarg.h>
  21. #include <io.h>
  22. #include <fcntl.h>
  23. #include "program.h"
  24. #include "graphgng.h"
  25. #include "allocatg.h"
  26. #include "graphgnl.h"
  27. #include "mousedrv.h"
  28.  
  29. #define  SINGLEPAGE
  30.  
  31. extern int MouseExists;                   /* Responsibility of program! */
  32. extern int GraphDriver;                               /* "" */
  33.  
  34. int    GraphMode;                 /* The Graphics mode value. */
  35. double AspectRatio;           /* Aspect ratio of a pixel on the screen. */
  36. int    ScreenMaxX, ScreenMaxY;        /* The maximum resolution of the screen. */
  37. int    ScreenMaxY2;                       /* ScreenMaxY / 2. */
  38. int    ScreenMaxColors;               /* The maximum # of colors available. */
  39. int    ScreenMaxPages;            /* The maximum # of pages available. */
  40. int    ScreenErrorCode;                 /* Reports any graphics errors. */
  41. int    CurrentCursorX, CurrentCursorY;         /* Cursor current position. */
  42. int    ScreenGraphicMode = FALSE;     /* TRUE if the screen in graphic mode. */
  43.  
  44. static double WndwAspectRatio, GlblAspectRatio;
  45. static struct palettetype palette;           /* Used to read palette info. */
  46. static char *CursorImageBuffer;                    /* Cursor shape. */
  47. static int LocalMoveToX, LocalMoveToY;          /* Save last position we move. */
  48. static char LastGetChar;        /* Last char recieved in UpdateGetPoint. */
  49. static double MouseXRatio, MouseYRatio;
  50. static int DefaultFontSize;                /* Depend on graphic driver. */
  51. static int ScreenCursorColor;        /* Graphic and text (in graphic screen). */
  52. static int ViewPortX, ViewPortY;    /* Viewport offset from top left (0, 0). */
  53. static int OldStdOut;      /* To recover stdout when we done with graph mode. */
  54. static int CrntWindowName;         /* Unique index for current window. */
  55.  
  56. /* #define NOGRAPHICS      /* If no graphics to perform (only routine calls). */
  57. /* #define DEBUG           /* Print graphics driver info and dies... */
  58.  
  59. /****************************************************************************
  60. * Routine to move to a normalized point    between    -1..1 on both axes :        *
  61. ****************************************************************************/
  62. void GGMyMove(double x, double y)
  63. {
  64. #ifndef    NOGRAPHICS
  65.     /* Note I use ScreenMaxY2 as X>ScreenMaxY2 left for    text (menus). */
  66.     LocalMoveToX = (int) ((x * WndwAspectRatio * ScreenMaxY2 + ScreenMaxY2) *
  67.                             GlblAspectRatio);
  68.     LocalMoveToY = (int) (-y * ScreenMaxY2 + ScreenMaxY2);
  69.     moveto(LocalMoveToX - ViewPortX, LocalMoveToY - ViewPortY);
  70. #endif /* NOGRAPHICS */
  71. }
  72.  
  73. /****************************************************************************
  74. * Routine to draw to a normalized point    between    -1..1 on both axes :        *
  75. ****************************************************************************/
  76. void GGMyDraw(double x, double y)
  77. {
  78. #ifndef    NOGRAPHICS
  79.     int    NewX, NewY;
  80.  
  81.     /* Note I use ScreenMaxY2 as X>ScreenMaxY2 left for    text (menus). */
  82.     NewX = (int) ((x * WndwAspectRatio * ScreenMaxY2 + ScreenMaxY2) *
  83.                             GlblAspectRatio);
  84.     NewY = (int) (-y * ScreenMaxY2 + ScreenMaxY2);
  85.     line(LocalMoveToX - ViewPortX, LocalMoveToY - ViewPortY,
  86.                     NewX - ViewPortX, NewY - ViewPortY);
  87.     LocalMoveToX = NewX;
  88.     LocalMoveToY = NewY;
  89. #endif /* NOGRAPHICS */
  90. }
  91.  
  92. /****************************************************************************
  93. * Routine to draw to a normelized point    between    -1..1 on both axes :        *
  94. ****************************************************************************/
  95. void GGMySetColor(int color)
  96. {
  97. #ifndef    NOGRAPHICS
  98.     if (color >= ScreenMaxColors) color = color % (ScreenMaxColors-1) + 1;
  99.     setcolor(color);
  100. #endif /* NOGRAPHICS */
  101. }
  102.  
  103. /****************************************************************************
  104. * Routine to reset all the system to starting condition    :            *
  105. ****************************************************************************/
  106. void GGInitGraph(void)
  107. {
  108. #ifndef    NOGRAPHICS
  109.     int    xasp, yasp,               /* Used to read the aspect ratio. */
  110.     i, j;
  111.  
  112.     if (registerbgidriver(Herc_driver) < 0) MyExit(1);
  113.     if (registerbgidriver(EGAVGA_driver) < 0) MyExit(1);
  114.  
  115.     /* For some wierd reason, some machines waits much more than expected on */
  116.     /* the first delay. Lets do it now, so people will consider it part of   */
  117.     /* the initialization (make it a feature...)...                          */
  118.     delay(1);
  119.  
  120.     if (GraphDriver == 0) {
  121.     /* Use autodetect feature of graphic library to see what we have. */
  122.     detectgraph(&GraphDriver, &GraphMode);
  123.     if (GraphDriver < 0) {
  124.         fprintf(stderr, "Auto detect: No graphics device detected\n");
  125.         MyExit(1);
  126.     }
  127.     }
  128.  
  129.     /* Put in the following any graphic driver specific setup: */
  130.     switch (GraphDriver) {
  131.     case EGA:
  132.         GraphMode = EGAHI;
  133.         break;
  134.     case EGA64:
  135.         GraphMode = EGA64HI;
  136.         break;
  137.     case EGAMONO:
  138.         GraphMode = EGAMONOHI;
  139.         break;
  140.     case HERCMONO:
  141.         GraphMode = HERCMONOHI;
  142.         break;
  143.     case VGA:
  144.         GraphMode = VGAHI;
  145.         break;
  146.     default:
  147.         fprintf(stderr, "Requested graphic device (%d - see .cfg file) is not supported\n",
  148.         GraphDriver);
  149.         MyExit(1);
  150.         break;
  151.     }
  152.  
  153.     initgraph(&GraphDriver, &GraphMode, "");
  154.     ScreenErrorCode = graphresult();       /* Read result of initialization. */
  155.     if (ScreenErrorCode != grOk) {           /* Error occured during init. */
  156.     fprintf(stderr, " Graphics System Error: %s\n",
  157.                 grapherrormsg(ScreenErrorCode));
  158.     MyExit(1);
  159.     }
  160.  
  161.     getpalette(&palette);             /* Read the palette from board. */
  162.     ScreenMaxColors = getmaxcolor() + 1;   /* Read maximum number of colors. */
  163.     ScreenCursorColor = (ScreenMaxColors > 1 ? ScreenMaxColors - 1 :
  164.                            ScreenMaxColors);
  165.  
  166.     ScreenMaxX = getmaxx();                 /* Read size of screen. */
  167.     ScreenMaxY = getmaxy();
  168.     ScreenMaxY2 = ScreenMaxY / 2;
  169.     CurrentCursorX = ScreenMaxX / 2;
  170.     CurrentCursorY = ScreenMaxY2;
  171.     getaspectratio(&xasp, &yasp);        /* Read the hardware aspect. */
  172.     /* Get correction factor: */
  173.     AspectRatio = (double) xasp / (double) yasp;
  174.     GlblAspectRatio = 1.0 / AspectRatio;
  175.     WndwAspectRatio = 1.0;
  176.  
  177.     /* Put in the following any graphic driver specific setup: */
  178.     switch (GraphDriver) {
  179.     case HERCMONO:
  180.         DefaultFontSize = 1;            /* Fixed width font. */
  181.         ScreenMaxPages = 2;
  182.         break;
  183.  
  184.     case EGA:
  185.         DefaultFontSize = 1;            /* Fixed width font. */
  186.         ScreenMaxPages = 2;
  187.  
  188.         GlblAspectRatio = 1.2; /* I dont like it either, but its simple. */
  189.         break;
  190.  
  191.     case EGA64:
  192.         DefaultFontSize = 1;            /* Fixed width font. */
  193.         ScreenMaxPages = 1;
  194.  
  195.         GlblAspectRatio = 1.2; /* I dont like it either, but its simple. */
  196.         break;
  197.  
  198.     case EGAMONO:
  199.         DefaultFontSize = 1;            /* Fixed width font. */
  200.         ScreenMaxPages = 2;
  201.         ScreenMaxColors = 2;
  202.  
  203.         GlblAspectRatio = 1.2; /* I dont like it either, but its simple. */
  204.         break;
  205.  
  206.     case VGA:
  207.         DefaultFontSize = 1;            /* Fixed width font. */
  208.         ScreenMaxPages = 2;
  209.  
  210.         GlblAspectRatio = 0.88;/* I dont like it either, but its simple. */
  211.         break;
  212.     }
  213.  
  214. #   ifdef SINGLEPAGE
  215.     ScreenMaxPages = 1;
  216. #   endif /* SINGLEPAGE */
  217.  
  218. #   ifdef DEBUG
  219.     GGCloseGraph();
  220.     fprintf(stderr, "ScreenMaxX = %d, ScreenMaxY = %d, MaxColors = %d\n",
  221.         ScreenMaxX, ScreenMaxY, ScreenMaxColors);
  222.     fprintf(stderr, "AspectRatio = %lf, ViewPortX = %d, ViewPortY = %d\n",
  223.         AspectRatio, ViewPortX, ViewPortY);
  224.     MyExit(1);
  225. #   endif /* DEBUG */
  226.  
  227.     /* Prepare the cursor (Arrow) image : */
  228.     cleardevice();
  229.     GGMySetColor(ScreenCursorColor);
  230.     setlinestyle(SOLID_LINE, 0,    NORM_WIDTH);
  231.     line(0, 0, CURSOR_IMAGE_X, CURSOR_IMAGE_Y);
  232.     j = CURSOR_IMAGE_X / 3;
  233.     for    (i=1; i<=7; i++) line(0, 0, j, j + i);         /* Draw the arrow head. */
  234.     j = CURSOR_IMAGE_Y / 3;
  235.     for    (i=1; i<=7; i++) line(0, 0, j + i, j);
  236.  
  237.     CursorImageBuffer = MyMalloc(imagesize(0, 0, CURSOR_IMAGE_X,
  238.                          CURSOR_IMAGE_Y), OTHER_TYPE);
  239.     getimage(0,    0, CURSOR_IMAGE_X, CURSOR_IMAGE_Y, CursorImageBuffer);
  240.  
  241.     settextstyle(DEFAULT_FONT, HORIZ_DIR, DefaultFontSize);
  242.  
  243.     if (MouseExists) {
  244.     switch (GraphDriver) {
  245.         case EGA:
  246.         case EGA64:
  247.         case EGAMONO:
  248.         case VGA:
  249.         MSMouseXmax = 1000;            /* Set Column Range. */
  250.         MSMouseYmax = 1000;               /* Set Row range. */
  251.         break;
  252.         case HERCMONO:
  253.         /* Compensate on the text mode the mouse knows about as      */
  254.         /* hercules is not supported by the mouse driver!            */
  255.         MSMouseXmax = 8000;            /* Set Column Range. */
  256.         MSMouseYmax = 8000;               /* Set Row range. */
  257.         break;
  258.     }
  259.     MouseXRatio = ((double) ScreenMaxX) / MSMouseXmax;
  260.     MouseYRatio = ((double) ScreenMaxY) / MSMouseYmax;
  261.     }
  262.  
  263.     ScreenGraphicMode = TRUE;
  264.     i = open("nul", O_WRONLY);      /* Redirect the stdout to nul: (no ^C...). */
  265.     fflush(stdout);
  266.     OldStdOut = dup(1);
  267.     dup2(i, 1);
  268.     close(i);
  269. #endif /* NOGRAPHICS */
  270. }
  271.  
  272. /****************************************************************************
  273. * Routine to close and shutdown    graphic    mode :                    *
  274. ****************************************************************************/
  275. void GGCloseGraph(void)
  276. {
  277. #ifndef    NOGRAPHICS
  278.     closegraph();              /* Return the system to text mode. */
  279.     ScreenGraphicMode = FALSE;
  280.     dup2(OldStdOut, 1);            /* Recover stdout to its regular status. */
  281.     close(OldStdOut);
  282. #endif /* NOGRAPHICS */
  283. }
  284.  
  285. /****************************************************************************
  286. * Routine to update x, y coordinates according to current x, y and key        *
  287. * pressed. Returns TRUE only if <Enter> or alpha char is pressed.        *
  288. ****************************************************************************/
  289. static int GGUpdateGetPointKbd(int *x, int *y)
  290. {
  291.     int    BrkPressed = FALSE;
  292.  
  293.     switch (LastGetChar    = getch()) {
  294.     case 0:
  295.         switch(getch()) {                  /* extended character: */
  296.         case 16:
  297.             MyExit(0);              /* Alt - Q, async. exit... */
  298.         case 71:
  299.             *x -= 1;              /* Arrowes - move 1 at a time. */
  300.             *y -= 1;
  301.             break;
  302.         case 72:
  303.             *y -= 1;
  304.             break;
  305.         case 73:
  306.             *x += 1;
  307.             *y -= 1;
  308.             break;
  309.         case 75:
  310.             *x -= 1;
  311.             break;
  312.         case 77:
  313.             *x += 1;
  314.             break;
  315.         case 79:
  316.             *x -= 1;
  317.             *y += 1;
  318.             break;
  319.         case 80:
  320.             *y += 1;
  321.             break;
  322.         case 81:
  323.             *x += 1;
  324.             *y += 1;
  325.             break;
  326.         }
  327.         break;
  328.     case 10 :
  329.     case 13 :
  330.         BrkPressed = TRUE;
  331.         break;
  332.     case '1':
  333.         *x -= 10;              /* Shifted arrows - move 10 at a time. */
  334.         *y += 10;
  335.         break;
  336.     case '2':
  337.         *y += 10;
  338.         break;
  339.     case '3':
  340.         *x += 10;
  341.         *y += 10;
  342.         break;
  343.     case '4':
  344.         *x -= 10;
  345.         break;
  346.     case '6':
  347.         *x += 10;
  348.         break;
  349.     case '7':
  350.         *x -= 10;
  351.         *y -= 10;
  352.         break;
  353.     case '8':
  354.         *y -= 10;
  355.         break;
  356.     case '9':
  357.         *x += 10;
  358.         *y -= 10;
  359.         break;
  360.     /* If the key pressed is an alpha - exit. */
  361.     default:
  362.         if isalpha(LastGetChar) BrkPressed = TRUE;
  363.         break;
  364.     }
  365.  
  366.     return BrkPressed;
  367. }
  368.  
  369. /****************************************************************************
  370. * Routine to get one x, y selected point in normelized form (-1..1) :        *
  371. ****************************************************************************/
  372. void GGGetPoint(double *x, double *y)
  373. {
  374. #ifndef    NOGRAPHICS
  375.     int    Xtemp, Ytemp, Buttons, Xscreen, Yscreen, Quit, GetInput;
  376.     struct viewporttype view;
  377.  
  378.     getviewsettings(&view);
  379.     setviewport(0, 0, getmaxx(), getmaxy(), FALSE);
  380.  
  381.     LastGetChar = 0x001;         /* Make in impossible if mouse input... */
  382.  
  383.     Xtemp = CurrentCursorX;
  384.     Ytemp = CurrentCursorY;
  385.     putimage(CurrentCursorX,         /* Draw the cursor - starting position. */
  386.          CurrentCursorY, CursorImageBuffer,    XOR_PUT);
  387.  
  388.     if (MouseExists)            /* Update mouse on current position. */
  389.     MouseSetPosition((int) (CurrentCursorX / MouseXRatio),
  390.              (int) (CurrentCursorY / MouseYRatio));
  391.  
  392.     Quit = FALSE;
  393.     do {
  394.     GetInput = FALSE;
  395.     do {
  396.         /* Wait for input from one of the devices: Mouse/Keyboard. */
  397.         if (MouseExists && MouseQueryBuffer()) {
  398.         MouseGetBuffer(&Xscreen, &Yscreen, &Buttons);
  399.         GetInput = TRUE;
  400.         CurrentCursorX = (int) (Xscreen * MouseXRatio);
  401.         CurrentCursorY = (int) (Yscreen * MouseYRatio);
  402.         Quit = Buttons & 0x01;
  403.         }
  404.         if (kbhit()) {
  405.         Quit = GGUpdateGetPointKbd(&CurrentCursorX, &CurrentCursorY);
  406.         if (MouseExists)        /* Update mouse on the new position. */
  407.             MouseSetPosition((int) (CurrentCursorX / MouseXRatio),
  408.                                       (int) (CurrentCursorY / MouseYRatio));
  409.         GetInput = TRUE;
  410.         }
  411.  
  412.     }
  413.     while (!GetInput);
  414.     if (CurrentCursorX < 0) CurrentCursorX = 0;
  415.     if (CurrentCursorY < 0) CurrentCursorY = 0;
  416.     if (CurrentCursorX > ScreenMaxX - CURSOR_IMAGE_X)
  417.         CurrentCursorX = ScreenMaxX    - CURSOR_IMAGE_X;
  418.     if (CurrentCursorY > ScreenMaxY    - CURSOR_IMAGE_Y / 2)
  419.         CurrentCursorY = ScreenMaxY - CURSOR_IMAGE_Y / 2;
  420.  
  421.     putimage(Xtemp, Ytemp, CursorImageBuffer, XOR_PUT);/* Erase old crsr!*/
  422.     putimage(CurrentCursorX, CurrentCursorY, CursorImageBuffer,
  423.                          XOR_PUT); /* Draw new crsr! */
  424.     Xtemp = CurrentCursorX;        /* Save them so we could erase it later. */
  425.     Ytemp = CurrentCursorY;
  426.     }
  427.     while (!Quit);
  428.  
  429.     putimage(Xtemp,            /* Erase last old cursor before quiting. */
  430.          Ytemp, CursorImageBuffer, XOR_PUT);
  431.  
  432.     /* See GGMyMove for ScreenMaxY2. */
  433.     *x = ((double)(CurrentCursorX) / GlblAspectRatio - ScreenMaxY2) /
  434.                                 ScreenMaxY2;
  435.     *y = ((double)(CurrentCursorY) - ScreenMaxY2) / (-ScreenMaxY2);
  436.  
  437.     setviewport(view.left, view.top, view.right, view.bottom, view.clip);
  438.  
  439. #endif /* NOGRAPHICS */
  440. }
  441.  
  442. /****************************************************************************
  443. * Routine to draw a point on screen as marker +    with a title :            *
  444. ****************************************************************************/
  445. void GGDrawPoint(double p[], char title[], int PointColor)
  446. {
  447. #ifndef    NOGRAPHICS
  448.     GGMySetColor(PointColor);
  449.     GGMyMove(p[1] + POINT_SIZE, p[2]);
  450.     GGMyDraw(p[1] - POINT_SIZE, p[2]);
  451.     GGMyMove(p[1], p[2] + POINT_SIZE);
  452.     GGMyDraw(p[1], p[2] - POINT_SIZE);
  453.  
  454.     GGXYPutStr(p[1] + POINT_TITLE, p[2] + POINT_TITLE, title);
  455. #endif /* NOGRAPHICS */
  456. }
  457.  
  458. /*****************************************************************************
  459. *    Routine to set up the view port.                         *
  460. *****************************************************************************/
  461. void GGWindowViewPort(double XMin, double YMin,
  462.               double XMax, double YMax, int WindowName)
  463. {
  464. #ifndef    NOGRAPHICS
  465.     CrntWindowName = WindowName;
  466.     switch (WindowName) {
  467.     case NO_WINDOW_NAME:
  468.         break;
  469.     case INPUT_WINDOW_NAME:
  470.         WndwAspectRatio = 1.0;
  471.         break;
  472.     case STATUS_WINDOW_NAME:
  473.         WndwAspectRatio = 1.0;
  474.         break;
  475.     case VIEW_WINDOW_NAME:
  476.         WndwAspectRatio = 1.2;
  477.         break;
  478.     }
  479.  
  480.     setviewport(
  481.     (ViewPortX = (int) ((XMin * ScreenMaxY2 + ScreenMaxY2) *
  482.                             GlblAspectRatio)),
  483.     (ViewPortY = (int) (-YMax * ScreenMaxY2 + ScreenMaxY2)),
  484.     (int) ((XMax * ScreenMaxY2 + ScreenMaxY2) * GlblAspectRatio),
  485.     (int) (-YMin * ScreenMaxY2 + ScreenMaxY2),
  486.     TRUE);
  487. #endif /* NOGRAPHICS */
  488. }
  489.  
  490. /*****************************************************************************
  491. *   Routine to clear given window area.                         *
  492. * Note the viewport on exit is the window only!                     *
  493. *****************************************************************************/
  494. void GGClearWindow(double XMin, double YMin,
  495.            double XMax, double YMax, int WindowName)
  496. {
  497. #ifndef    NOGRAPHICS
  498.     GGWindowViewPort(XMin, YMin, XMax, YMax, WindowName);
  499.     clearviewport();
  500. #endif /* NOGRAPHICS */
  501. }
  502.  
  503. /*****************************************************************************
  504. *   Routine to clear all the screen.                         *
  505. *****************************************************************************/
  506. void GGClearAllScreen(void)
  507. {
  508. #ifndef    NOGRAPHICS
  509.     cleardevice();
  510.     ViewPortX = ViewPortY = 0;
  511. #endif /* NOGRAPHICS */
  512. }
  513.  
  514. /*****************************************************************************
  515. * Routine to put one char in current position with given color:             *
  516. * The position of the cursor is updated horizontally (only).             *
  517. * If the char is BS (Back Space), the position is updated backward with no   *
  518. * printing. Note it is assume no over/underflow of horizontal position.         *
  519. *****************************************************************************/
  520. void GGXYPutChar(char c, int Color)
  521. {
  522. #ifndef    NOGRAPHICS
  523.     char c1[] = " ";                   /* One char in length string. */
  524.  
  525.     if (c == BSPACE) {
  526.     LocalMoveToX -= textwidth(" ");          /* Must be non justified font! */
  527.     moveto(LocalMoveToX - ViewPortX, LocalMoveToY - ViewPortY);
  528.     }
  529.     else {
  530.     c1[0] = c;
  531.     GGMySetColor(Color);
  532.     outtext(c1);
  533.     LocalMoveToX += textwidth(" ");          /* Must be non justified font! */
  534.     moveto(LocalMoveToX - ViewPortX, LocalMoveToY - ViewPortY);
  535.     }
  536. #endif /* NOGRAPHICS */
  537. }
  538.  
  539. /*****************************************************************************
  540. * Routine to print an message on the given location:                 *
  541. *****************************************************************************/
  542. void GGXYPutStr(double x, double y, char *s)
  543. {
  544. #ifndef    NOGRAPHICS
  545.     GGMyMove(x, y);
  546.     outtext(s);
  547. #endif /* NOGRAPHICS */
  548. }
  549.  
  550. /*****************************************************************************
  551. * Routine to read one line terminated by <Enter> and visualized    on graphic   *
  552. * screen.                                     *
  553. * Full line editing is supported which includes:                 *
  554. * 1. Right and left arrow to move along the line.                 *
  555. * 2. Delete to delete current character.                     *
  556. * 3. Insert to toggle Insert/Overwrite mode.                     *
  557. * 4. Backspace to delete character before current one.                 *
  558. * 5. Home/End to move to beginning/End of string respectively.             *
  559. * 6. Return to accept current line.                         *
  560. * 7. Esc to clear current line.                             *
  561. * If s is not empty it is used as starting string.                 *
  562. * Line is drawn    starting from position x, y on screen (normalized -1..1).    *
  563. *****************************************************************************/
  564. void GGGetGraphicLine(double x, double y, char s[], int Length, int Color)
  565. {
  566. #ifndef    NOGRAPHICS
  567.     static int Insert = TRUE;
  568.     int    NextKey, Xstep, CursorPos = 0, FirstVisible = 0, Len = strlen(s),
  569.     EndOfString = FALSE, FirstTime = s[0];
  570.     char *Cursor;
  571.  
  572.     /* Force the string to be empty. Note we saved s[0] in FirstTime, so if  */
  573.     /* the string is empty we change nothing, otherwise we can recover it.   */
  574.     s[0] = 0;
  575.  
  576.     Xstep = textwidth(" ");     /* Get the width is pixels of current font. */
  577.  
  578.     while (!EndOfString) {
  579.     if (Len >= Length) {
  580.         s[Length-1] = 0;
  581.         return;
  582.     }
  583.  
  584.     /* Set the first character in string to be displayed: */
  585.     FirstVisible = CursorPos > 70 ? CursorPos - 10 : 0;
  586.     GGMySetColor(Color);          /* Draw the string and the cursor: */
  587.     GGXYPutStr(x, y, &s[FirstVisible]);
  588.     Cursor = (Insert ? "_" : "-");
  589.     GGMySetColor(ScreenCursorColor);
  590.     GGMyMove(x, y);
  591.     moverel((CursorPos - FirstVisible) * Xstep, 0);
  592.     outtext(Cursor);
  593.  
  594.     NextKey = GGGetKey();
  595.  
  596.     GGMySetColor(BLACK);         /* Erase the string and the cursor: */
  597.     GGMyMove(x, y);
  598.     moverel((CursorPos - FirstVisible) * Xstep, 0);
  599.     outtext(Cursor);
  600.     GGXYPutStr(x, y, &s[FirstVisible]);
  601.  
  602.     switch (NextKey) {
  603.         case KEY_BSPACE:
  604.         if (CursorPos == 0) {
  605.             GGTone(1000, 100);             /* Do some noise... */
  606.             break;
  607.         }
  608.         movmem(&s[CursorPos], &s[CursorPos - 1], Len - CursorPos + 1);
  609.         CursorPos--;
  610.         Len--;
  611.         break;
  612.         case KEY_DELETE:
  613.         if (CursorPos >= Len) {
  614.             GGTone(1000, 100);             /* Do some noise... */
  615.             break;
  616.         }
  617.         movmem(&s[CursorPos + 1], &s[CursorPos], Len - CursorPos);
  618.         Len--;
  619.         break;
  620.         case KEY_RIGHT:
  621.         if (CursorPos >= Len) {
  622.             GGTone(1000, 100);             /* Do some noise... */
  623.             break;
  624.         }
  625.         CursorPos++;
  626.         break;
  627.         case KEY_LEFT:
  628.         if (CursorPos <= 0) {
  629.             GGTone(1000, 100);             /* Do some noise... */
  630.             break;
  631.         }
  632.         CursorPos--;
  633.         break;
  634.         case KEY_UP:
  635.         if (FirstTime) s[0] = FirstTime;
  636.         break;
  637.         case KEY_RETURN:
  638.         EndOfString = TRUE;
  639.         break;
  640.         case KEY_ESC:
  641.         Len = 0;                /* Clear everything. */
  642.         CursorPos = 0;
  643.         s[0] = 0;
  644.         break;
  645.         case KEY_HOME:
  646.         CursorPos = 0;
  647.         break;
  648.         case KEY_END:
  649.         CursorPos = Len;
  650.         break;
  651.         case KEY_INSERT:
  652.         Insert = !Insert;
  653.         break;
  654.         default:                      /* Regular ascii char. */
  655.         if (Insert) {
  656.             movmem(&s[CursorPos], &s[CursorPos + 1],
  657.                             Len - CursorPos + 1);
  658.             Len++;
  659.         }
  660.         else if (CursorPos == Len) Len++;/* We are on last character.*/
  661.         s[CursorPos++] = NextKey;
  662.         if (CursorPos == Len) s[CursorPos] = 0;
  663.         break;
  664.     }
  665.     FirstTime = FALSE;
  666.     }
  667. #endif /* NOGRAPHICS */
  668. }
  669.  
  670. /*****************************************************************************
  671. * Get a key from keyboard, and translating operational keys into special     *
  672. * codes (>255).                                     *
  673. *****************************************************************************/
  674. static int GGGetKey(void)
  675. {
  676.     char c;
  677.  
  678.     while (TRUE) switch (c = getch()) {
  679.     case 0:              /* Extended code - get the next extended char. */
  680.         switch (getch()) {
  681.         case 75: return KEY_LEFT;
  682.         case 77: return KEY_RIGHT;
  683.         case 71: return KEY_HOME;
  684.         case 72: return KEY_UP;
  685.         case 79: return KEY_END;
  686.         case 83: return KEY_DELETE;
  687.         case 82: return KEY_INSERT;
  688.         }
  689.         break;
  690.     case 8:
  691.         return KEY_BSPACE;
  692.     case 10:
  693.     case 13:
  694.         return KEY_RETURN;
  695.     case 27:
  696.         return KEY_ESC;
  697.     default:
  698.         if isprint(c) return c;
  699.     }
  700.  
  701.     return KEY_RETURN;                    /* Make warnings silent. */
  702. }
  703.  
  704. /*****************************************************************************
  705. * Routine to make some sound with given Frequency, Time milliseconds:         *
  706. *****************************************************************************/
  707. void GGTone(int Frequency, int Time)
  708. {
  709.     sound(Frequency);
  710.     delay(Time);
  711.     nosound();
  712. }
  713.