home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmos2002.zip / SRC / GWINDOWS.MOD < prev    next >
Text File  |  1996-11-08  |  22KB  |  615 lines

  1. IMPLEMENTATION MODULE GWindows;
  2.  
  3.         (********************************************************)
  4.         (*                                                      *)
  5.         (*          Windows module for screen graphics          *)
  6.         (*                                                      *)
  7.         (*  Programmer:         P. Moylan                       *)
  8.         (*  Last edited:        7 November 1996                 *)
  9.         (*  Status:                                             *)
  10.         (*      Points, lines, and text working.                *)
  11.         (*      Still adding more features.                     *)
  12.         (*      Now working on scrolling, setting cursor, etc.  *)
  13.         (*                                                      *)
  14.         (********************************************************)
  15.  
  16. FROM Graphics IMPORT
  17.     (* type *)  ColourType,
  18.     (* proc *)  SetMode, SetDefaultMode, GetScreenShape;
  19.  
  20. FROM Storage IMPORT
  21.     (* proc *)  ALLOCATE, DEALLOCATE;
  22.  
  23. FROM ScreenGeometry IMPORT
  24.     (* type *)  Point, Rectangle,
  25.     (* proc *)  Inside, TrimLine;
  26.  
  27. FROM Tiles IMPORT
  28.     (* type *)  TileSet,
  29.     (* proc *)  CreateTileSet, DiscardTileSet, AddPoint, AddLine,
  30.                 AddRectangle, AddString, ClearTileSet, ScrollContents,
  31.                 AddRotatedString, TileSetMemory;
  32.  
  33. FROM Keyboard IMPORT
  34.     (* proc *)  InKey;
  35.  
  36. FROM FinalExit IMPORT
  37.     (* proc *)  TerminationMessage;
  38.  
  39. (************************************************************************)
  40.  
  41. TYPE
  42.     (* A window is described by a record with the following fields.     *)
  43.     (*  absborder       the outside edge of the window, in absolute     *)
  44.     (*                  (i.e. screen-relative) coordinates.             *)
  45.     (*  databorder      the rectangle, in screen-relative coordinates,  *)
  46.     (*                  outside which data should not be plotted.       *)
  47.     (*  tiles           the set of tiles making up the window.          *)
  48.     (*  background      the background colour for the window.           *)
  49.     (*  foreground      the foreground colour for the window.           *)
  50.     (*  cursor          the text cursor, in terms of points.            *)
  51.     (*  row, column     the text cursor, in terms of characters.        *)
  52.     (*  ScrollRegion    the "normal" region for text, measured in       *)
  53.     (*                    terms of character positions.                 *)
  54.  
  55.     Window = POINTER TO
  56.                 RECORD
  57.                     absborder, databorder: Rectangle;
  58.                     tiles: TileSet;
  59.                     background, foreground: ColourType;
  60.                     cursor: Point;
  61.  
  62.                     (* The following fields are in units of characters  *)
  63.                     (* rather than (x,y) coordinates.                   *)
  64.  
  65.                     row, column: INTEGER;
  66.                     ScrollRegion: Rectangle;
  67.  
  68.                 END (*RECORD*);
  69.  
  70. (************************************************************************)
  71.  
  72. VAR
  73.     (* Maximum screen coordinates and colour for the selected mode.     *)
  74.     (* (Minimum value is zero in all three cases.)                      *)
  75.  
  76.     XMAX, YMAX, CharHeight: CARDINAL;
  77.     MaxColour: ColourType;
  78.  
  79. (************************************************************************)
  80. (*                      OPENING AND CLOSING WINDOWS                     *)
  81. (************************************************************************)
  82.  
  83. PROCEDURE DrawFrame (w: Window);
  84.  
  85.     (* Draws the window frame.  Used when first opening a window, or    *)
  86.     (* for putting back the frame after clearing the window.            *)
  87.  
  88.     VAR R: Rectangle;
  89.  
  90.     BEGIN
  91.         WITH w^ DO
  92.             AddRectangle (tiles, absborder, foreground);
  93.             IF databorder.left <> absborder.left+1 THEN
  94.                 R := databorder;
  95.                 WITH R DO
  96.                     DEC(left);  INC (right);
  97.                     DEC(bottom);  INC (top);
  98.                 END (*WITH*);
  99.                 AddRectangle (tiles, R, foreground);
  100.             END (*IF*);
  101.         END (*WITH*);
  102.     END DrawFrame;
  103.  
  104. (************************************************************************)
  105.  
  106. PROCEDURE OpenWindow (VAR (*OUT*) w: Window;
  107.                                 left, bottom, right, top: CARDINAL;
  108.                                 Foregrnd, Backgrnd: ColourType;
  109.                                 b: BorderType);
  110.  
  111.     (* Creates a new window.    *)
  112.  
  113.     VAR temp: CARDINAL;
  114.  
  115.     BEGIN
  116.         (* Make sure that the parameters are within the legal ranges.   *)
  117.  
  118.         IF left > XMAX THEN left := XMAX END(*IF*);
  119.         IF right > XMAX THEN right := XMAX END(*IF*);
  120.         IF left > right THEN
  121.             temp := left;  left := right;  right := temp;
  122.         END (*IF*);
  123.         IF bottom > YMAX THEN bottom := YMAX END(*IF*);
  124.         IF top > YMAX THEN top := YMAX END(*IF*);
  125.         IF bottom > top THEN
  126.             temp := bottom;  bottom := top;  top := temp;
  127.         END (*IF*);
  128.  
  129.         IF Backgrnd > MaxColour THEN Backgrnd := MaxColour END (*IF*);
  130.         IF Foregrnd > MaxColour THEN Foregrnd := MaxColour END (*IF*);
  131.         IF Foregrnd = Backgrnd THEN
  132.             Foregrnd := (Backgrnd + 1) MOD (MaxColour + 1);
  133.         END (*IF*);
  134.  
  135.         NEW (w);
  136.         WITH w^ DO
  137.             background := Backgrnd;  foreground := Foregrnd;
  138.             absborder.left := left;
  139.             absborder.right := right;
  140.             absborder.bottom := bottom;
  141.             absborder.top := top;
  142.             databorder := absborder;
  143.             IF b = double THEN temp := 3
  144.             ELSE temp := 1;
  145.             END (*IF*);
  146.             WITH databorder DO
  147.                 INC (left, temp);  DEC (right, temp);
  148.                 INC (bottom, temp);  DEC (top, temp);
  149.             END (*WITH*);
  150.             WITH ScrollRegion DO
  151.                 left := 0;  top := 0;
  152.  
  153.                 (* The following two lines might need fine tuning.      *)
  154.  
  155.                 right := (databorder.right - databorder.left) DIV 8 - 1;
  156.                 bottom := (databorder.top - databorder.bottom)
  157.                                         DIV VAL(INTEGER,CharHeight) - 1;
  158.  
  159.             END (*WITH*);
  160.             tiles := CreateTileSet (absborder, background);
  161.         END (*WITH*);
  162.  
  163.         DrawFrame (w);
  164.         SetCursor (w, 0, 0);
  165.  
  166.     END OpenWindow;
  167.  
  168. (************************************************************************)
  169.  
  170. PROCEDURE OpenWindowR (VAR (*OUT*) w: Window;  location: Rectangle;
  171.                                         Foregrnd, Backgrnd: ColourType;
  172.                                         b: BorderType);
  173.  
  174.     (* Same as OpenWindow, except for method of specifying location.    *)
  175.  
  176.     BEGIN
  177.         WITH location DO
  178.             IF left < 0 THEN left := 0 END(*IF*);
  179.             IF right < 0 THEN right := 0 END(*IF*);
  180.             IF bottom < 0 THEN bottom := 0 END(*IF*);
  181.             IF top < 0 THEN top := 0 END(*IF*);
  182.             OpenWindow (w, left, bottom, right, top, Backgrnd, Foregrnd, b);
  183.         END (*WITH*);
  184.     END OpenWindowR;
  185.  
  186. (************************************************************************)
  187.  
  188. PROCEDURE WindowMemory (w: Window;  memory: BOOLEAN);
  189.  
  190.     (* Specifying a FALSE value for the memory parameter means that     *)
  191.     (* subsequent data sent to this window will be written to the       *)
  192.     (* screen but not remembered.  This saves time and memory, the only *)
  193.     (* penalty being that data covered by an overlapping window will    *)
  194.     (* be lost.  Specifying TRUE restores the default condition, where  *)
  195.     (* all window data are retained for refreshing the screen when      *)
  196.     (* necessary.                                                       *)
  197.  
  198.     BEGIN
  199.         TileSetMemory (w^.tiles, memory);
  200.     END WindowMemory;
  201.  
  202. (************************************************************************)
  203.  
  204. PROCEDURE CloseWindow (VAR (*INOUT*) w: Window);
  205.  
  206.     (* Destroys the window.     *)
  207.  
  208.     BEGIN
  209.         DiscardTileSet (w^.tiles);
  210.         DISPOSE (w);
  211.     END CloseWindow;
  212.  
  213. (************************************************************************)
  214. (*                           CLEARING A WINDOW                          *)
  215. (************************************************************************)
  216.  
  217. PROCEDURE ClearWindow (w: Window);
  218.  
  219.     (* Erases all data from w, but keeps it open.       *)
  220.  
  221.     BEGIN
  222.         ClearTileSet (w^.tiles);
  223.         DrawFrame (w);  SetCursor (w, 0, 0);
  224.     END ClearWindow;
  225.  
  226. (************************************************************************)
  227. (*                      SETTING THE FOREGROUND COLOUR                   *)
  228. (************************************************************************)
  229.  
  230. PROCEDURE SetColour (w: Window;  colour: ColourType);
  231.  
  232.     (* Specifies the foreground colour to be used until further notice. *)
  233.  
  234.     BEGIN
  235.         w^.foreground := colour;
  236.     END SetColour;
  237.  
  238. (************************************************************************)
  239. (*                           PLOTTING A POINT                           *)
  240. (************************************************************************)
  241.  
  242. PROCEDURE PutPixelC (w: Window;  p: Point;  c: ColourType);
  243.  
  244.     (* Plots a dot at the point (x,y) in window w.  The coordinates are *)
  245.     (* relative to the bottom left of the window.  If the dot lies      *)
  246.     (* outside the window it will be ignored.                           *)
  247.  
  248.     BEGIN
  249.         WITH w^ DO
  250.             INC (p.x, absborder.left);
  251.             INC (p.y, absborder.bottom);
  252.             IF Inside (p.x, p.y, databorder) THEN
  253.                 AddPoint (tiles, p, c);
  254.             END (*WITH*);
  255.         END (*WITH*);
  256.     END PutPixelC;
  257.  
  258. (************************************************************************)
  259.  
  260. PROCEDURE PutPixel (w: Window;  p: Point);
  261.  
  262.     (* Plots a dot at the point (x,y) in window w.  The coordinates are *)
  263.     (* relative to the bottom left of the window.  If the dot lies      *)
  264.     (* outside the window it will be ignored.                           *)
  265.  
  266.     BEGIN
  267.         WITH w^ DO
  268.             INC (p.x, absborder.left);
  269.             INC (p.y, absborder.bottom);
  270.             IF Inside (p.x, p.y, databorder) THEN
  271.                 AddPoint (tiles, p, foreground);
  272.             END (*WITH*);
  273.         END (*WITH*);
  274.     END PutPixel;
  275.  
  276. (************************************************************************)
  277.  
  278. PROCEDURE PutPixel2 (w: Window;  x, y: INTEGER);
  279.  
  280.     (* Same as PutPixel, with a different way of specifying the point.  *)
  281.  
  282.     VAR p: Point;
  283.  
  284.     BEGIN
  285.         p.x := x;  p.y := y;
  286.         PutPixel (w, p);
  287.     END PutPixel2;
  288.  
  289. (************************************************************************)
  290.  
  291. PROCEDURE PutPixel2C (w: Window;  x, y: INTEGER;  colour: ColourType);
  292.  
  293.     (* Same as PutPixel2, with the colour explicitly specified. *)
  294.  
  295.     VAR p: Point;
  296.  
  297.     BEGIN
  298.         p.x := x;  p.y := y;
  299.         PutPixelC (w, p, colour);
  300.     END PutPixel2C;
  301.  
  302. (************************************************************************)
  303. (*                      DRAWING A STRAIGHT LINE                         *)
  304. (************************************************************************)
  305.  
  306. PROCEDURE LineC (w: Window;  start, end: Point;  colour: ColourType);
  307.  
  308.     (* Draws a straight line.  The points are relative to the bottom    *)
  309.     (* left corner of w.  Parts of the line lying outside the window    *)
  310.     (* are clipped.                                                     *)
  311.  
  312.     BEGIN
  313.         WITH w^ DO
  314.             WITH absborder DO
  315.                 INC (start.x, left);  INC (start.y, bottom);
  316.                 INC (end.x, left);  INC (end.y, bottom);
  317.             END (*WITH*);
  318.             IF TrimLine (start, end, databorder) THEN
  319.                 AddLine (tiles, start, end, colour);
  320.             END (*IF*);
  321.         END (*WITH*);
  322.     END LineC;
  323.  
  324. (************************************************************************)
  325.  
  326. PROCEDURE Line (w: Window;  start, end: Point);
  327.  
  328.     (* Draws a straight line.  The points are relative to the bottom    *)
  329.     (* left corner of w.  Parts of the line lying outside the window    *)
  330.     (* are clipped.                                                     *)
  331.  
  332.     BEGIN
  333.         LineC (w, start, end, w^.foreground);
  334.     END Line;
  335.  
  336. (************************************************************************)
  337.  
  338. PROCEDURE Line2 (w: Window;  xstart, ystart, xend, yend: INTEGER);
  339.  
  340.     (* The same operation as Line, with a different way of specifying   *)
  341.     (* the parameters.                                                  *)
  342.  
  343.     VAR start, end: Point;
  344.  
  345.     BEGIN
  346.         start.x := xstart;  start.y := ystart;
  347.         end.x := xend;  end.y := yend;
  348.         Line (w, start, end);
  349.     END Line2;
  350.  
  351. (************************************************************************)
  352.  
  353. PROCEDURE Line2C (w: Window;  xstart, ystart, xend, yend: INTEGER;
  354.                                                         colour: ColourType);
  355.  
  356.     (* The same operation as Line2, but with the colour explicitly      *)
  357.     (* specified.                                                       *)
  358.  
  359.     VAR start, end: Point;
  360.  
  361.     BEGIN
  362.         start.x := xstart;  start.y := ystart;
  363.         end.x := xend;  end.y := yend;
  364.         LineC (w, start, end, colour);
  365.     END Line2C;
  366.  
  367. (************************************************************************)
  368.  
  369. PROCEDURE StringLength (VAR (*IN*) text: ARRAY OF CHAR): CARDINAL;
  370.  
  371.     (* Finds the true size of the text string, given that there *)
  372.     (* could be a nul terminator in the middle.                 *)
  373.  
  374.     VAR count: CARDINAL;
  375.  
  376.     BEGIN
  377.         count := 0;
  378.         WHILE (count <= HIGH(text)) AND (text[count] <> CHR(0)) DO
  379.             INC (count);
  380.         END (*WHILE*);
  381.         RETURN count;
  382.     END StringLength;
  383.  
  384. (************************************************************************)
  385.  
  386. PROCEDURE GString (w: Window;  x, y: CARDINAL;  text: ARRAY OF CHAR);
  387.  
  388.     (* Writes a horizontal character string at graphics position (x,y)  *)
  389.     (* relative to window w.  Characters which do not fit are not       *)
  390.     (* displayed.  This is not considered to be a text operation since  *)
  391.     (* the text cursor is not affected and there is no line wrap.       *)
  392.  
  393.     VAR count: CARDINAL;  place: Point;
  394.  
  395.     BEGIN
  396.         count := StringLength (text);
  397.         IF count = 0 THEN RETURN END(*IF*);
  398.  
  399.         (* Add the string to the TileSet.       *)
  400.  
  401.         WITH w^ DO
  402.             place.x := x + VAL(CARDINAL,absborder.left);
  403.             place.y := y + VAL(CARDINAL,absborder.bottom);
  404.             AddString (tiles, place, text, count, foreground, databorder);
  405.         END (*WITH*);
  406.  
  407.     END GString;
  408.  
  409. (************************************************************************)
  410.  
  411. PROCEDURE GStringUp (w: Window;  x, y: CARDINAL;  text: ARRAY OF CHAR);
  412.  
  413.     (* Like GString, but the string is rotated counterclockwise by      *)
  414.     (* 90 degrees, i.e. it is written in the +Y direction.              *)
  415.  
  416.     VAR count: CARDINAL;  place: Point;
  417.  
  418.     BEGIN
  419.         count := StringLength (text);
  420.         IF count = 0 THEN RETURN END(*IF*);
  421.  
  422.         (* Add the string to the TileSet.       *)
  423.  
  424.         WITH w^ DO
  425.             place.x := x + VAL(CARDINAL,absborder.left);
  426.             place.y := y + VAL(CARDINAL,absborder.bottom);
  427.             AddRotatedString (tiles, place, text, count, foreground,
  428.                                                         databorder);
  429.         END (*WITH*);
  430.  
  431.     END GStringUp;
  432.  
  433. (************************************************************************)
  434. (*                          TEXT OPERATIONS                             *)
  435. (************************************************************************)
  436. (*                                                                      *)
  437. (*  Every open window has a "text cursor" which is used only for text   *)
  438. (*  operations and is independent of any operations on dots and lines.  *)
  439. (*  The text cursor is updated after any text operation in such a way   *)
  440. (*  that the characters follow one another in the way one would expect  *)
  441. (*  for non-graphics windows.                                           *)
  442. (*                                                                      *)
  443. (************************************************************************)
  444.  
  445. PROCEDURE ComputeGraphicCursor (w: Window);
  446.  
  447.     (* Converts character position to graphics coordinates in w^.cursor *)
  448.  
  449.     BEGIN
  450.         WITH w^ DO
  451.             WITH cursor DO
  452.                 x := databorder.left + 8*column + 3;
  453.                 y := databorder.top - VAL(INTEGER,CharHeight)*(row+1) - 2;
  454.             END (*WITH*);
  455.         END (*WITH*);
  456.     END ComputeGraphicCursor;
  457.  
  458. (************************************************************************)
  459.  
  460. PROCEDURE SetCursor (w: Window;  row, column: CARDINAL);
  461.  
  462.     (* Sets the text cursor to the specified row and column.  The row   *)
  463.     (* and column are measured in units of characters (not pixels),     *)
  464.     (* with (0,0) representing the first character position at the      *)
  465.     (* upper left of the window.                                        *)
  466.  
  467.     BEGIN
  468.         w^.row := row;  w^.column := column;
  469.         ComputeGraphicCursor (w);
  470.     END SetCursor;
  471.  
  472. (************************************************************************)
  473.  
  474. PROCEDURE SaveCursor (w: Window;  VAR (*OUT*) row, column: CARDINAL);
  475.  
  476.     (* Returns the current row and column of the text cursor. *)
  477.  
  478.     BEGIN
  479.         row := w^.row;  column := w^.column;
  480.     END SaveCursor;
  481.  
  482. (************************************************************************)
  483.  
  484. PROCEDURE ScrollUp (w: Window);
  485.  
  486.     (* Moves all the text in w up by one line, discarding what falls    *)
  487.     (* off the top.                                                     *)
  488.  
  489.     BEGIN
  490.         ScrollContents (w^.tiles, CharHeight, w^.databorder);
  491.     END ScrollUp;
  492.  
  493. (************************************************************************)
  494.  
  495. PROCEDURE WriteLn (w: Window);
  496.  
  497.     (* Sets the text cursor to the start of the next text line down.    *)
  498.     (* If the cursor reaches the bottom of the window, the text in the  *)
  499.     (* window is scrolled.                                              *)
  500.  
  501.     BEGIN
  502.         WITH w^ DO
  503.             column := ScrollRegion.left;
  504.             IF row >= ScrollRegion.bottom THEN ScrollUp (w)
  505.             ELSE INC (row);
  506.             END (*IF*);
  507.         END (*WITH*);
  508.         ComputeGraphicCursor (w);
  509.     END WriteLn;
  510.  
  511. (************************************************************************)
  512.  
  513. PROCEDURE WriteString (w: Window;  text: ARRAY OF CHAR);
  514.  
  515.     (* Writes a horizontal character string at the current text cursor  *)
  516.     (* position for window w.  Characters which do not fit on the       *)
  517.     (* current line are wrapped around to a new row.                    *)
  518.  
  519.     VAR count, amount, pos, j, canfit: CARDINAL;
  520.  
  521.     BEGIN
  522.         amount := StringLength (text);
  523.         pos := 0;
  524.         WITH w^ DO
  525.             WITH ScrollRegion DO
  526.                 IF (amount = 0) OR (right < left) THEN RETURN END(*IF*);
  527.             END (*WITH*);
  528.             LOOP
  529.                 IF column > ScrollRegion.right THEN
  530.                     WriteLn (w);
  531.                 END (*IF*);
  532.                 canfit := ScrollRegion.right - column + 1;
  533.                 IF amount > canfit THEN count := canfit
  534.                 ELSE count := amount;
  535.                 END (*IF*);
  536.  
  537.                 AddString (tiles, cursor, text, count, foreground, databorder);
  538.                 INC (column, count);  INC (cursor.x, 8*count);
  539.  
  540.                 DEC (amount, count);
  541.                 IF amount = 0 THEN EXIT(*LOOP*) END(*IF*);
  542.  
  543.                 WriteLn (w);
  544.                 INC (pos, count);
  545.                 FOR j := 0 TO amount-1 DO
  546.                     text[j] := text[count+j];
  547.                 END (*FOR*);
  548.  
  549.             END (*LOOP*);
  550.  
  551.         END (*WITH*);
  552.  
  553.     END WriteString;
  554.  
  555. (************************************************************************)
  556.  
  557. PROCEDURE WriteChar (w: Window;  ch: CHAR);
  558.  
  559.     (* Writes a horizontal character at the current text cursor         *)
  560.     (* position for window w.  The text cursor is updated.              *)
  561.  
  562.     VAR buffer: ARRAY [0..0] OF CHAR;
  563.  
  564.     BEGIN
  565.         buffer[0] := ch;
  566.         WriteString (w, buffer);
  567.     END WriteChar;
  568.  
  569. (************************************************************************)
  570. (*                              SHUTDOWN                                *)
  571. (************************************************************************)
  572.  
  573. PROCEDURE ShutDown;
  574.  
  575.     VAR w: Window;  dummy: CHAR;
  576.         message: ARRAY [0..79] OF CHAR;
  577.  
  578.     BEGIN
  579.         (* For abnormal termination, put an error diagnostic on the     *)
  580.         (* screen.                                                      *)
  581.  
  582.         IF TerminationMessage(message) THEN
  583.             OpenWindow (w, 0,0, 300,30, 0, MaxColour, single);
  584.             WriteString (w, message);
  585.             dummy := InKey();
  586.             CloseWindow (w);
  587.         END (*IF*);
  588.  
  589.     END ShutDown;
  590.  
  591. (************************************************************************)
  592. (*                          INITIALISATION                              *)
  593. (************************************************************************)
  594.  
  595. PROCEDURE InitGraphics (mode: CARDINAL);
  596.  
  597.     (* Sets up the Graphics mode.  Optional, since the module starts up *)
  598.     (* with a best estimate of the "best" mode possible on the          *)
  599.     (* available hardware.                                              *)
  600.  
  601.     BEGIN
  602.         SetMode (mode, TRUE);
  603.         GetScreenShape (XMAX, YMAX, MaxColour, CharHeight);
  604.     END InitGraphics;
  605.  
  606. (************************************************************************)
  607.  
  608. BEGIN
  609.     SetDefaultMode;
  610.     GetScreenShape (XMAX, YMAX, MaxColour, CharHeight);
  611. FINALLY
  612.     ShutDown;
  613. END GWindows.
  614.  
  615.