'===========================================================================
' Subject: TEXT-BOXES W/BACKGROUND SAVES      Date: 02-23-98 (15:08)       
'  Author: Jonathan L. Leger                  Code: QB, QBasic, PDS        
'  Origin: leger@earthlink.net              Packet: TEXT.ABC
'===========================================================================
'*****************************************
'*** WINDOWS.BAS *** by Jonathan Leger ***   2/23/98
'********************************************************************
'*** I got back to the All BASIC Code Home Page a few days ago    ***
'*** and noticed some text-box routines out there.  They worked,  ***
'*** but were awfully slow and didn't seem to offer and saving/   ***
'*** restoring of the text behind the window options.  Well, here ***
'*** are some 100% QBASIC code routines for doing just that--and  ***
'*** very quickly, I might add. =)                                ***
'*** These windows also give the option of a shadow.  The shadow  ***
'*** actually shadows the character underneath the window (I did  ***
'*** notice one of the box routines also did this, but it was     ***
'*** pretty lethargic about it).                                  ***
'********************************************************************
'*** First, use ReadBuffer() to save what's behind the window you ***
'*** intend to open.                                              ***
'*** Next, use OpenWindow() to open that window.                  ***
'*** Finally, use WriteBuffer() to restore what was behind the    ***
'*** window you opened.                                           ***
'********************************************************************
'
'
'**********************************************************************
'*** As always, this code is freely released to the public.  Please ***
'*** give credit where credit is due if you use these routines. Any ***
'*** questions or comments can be directed to me at:                ***
'***                                                                ***
'***              leger@earthlink.net                               ***
'***                                                                ***
'***           Once again, thanks for keeping BASIC alive!          ***
'**********************************************************************

DEFINT A-Z

DECLARE SUB OpenWindow (style, x1, y1, x2, y2, fore, back, shadow)
DECLARE SUB ReadBuffer (x1, y1, x2, y2, buffer() AS INTEGER)
DECLARE SUB WriteBuffer (x1, y1, x2, y2, buffer() AS INTEGER)

'*** I went ahead and made the buffer large enough to store the
'*** entire screen's contents, though this is hardly necessary.
'*** The buffer must be setup like this: BUF([X WIDTH],[Y WIDTH],1 TO 2)
'*** The buffer routines check if you used the an option base of 1 or 0,
'*** so don't sweat that. BUF(X,Y,1) is the character, BUF(X,Y,2) is the
'*** color code.
DIM buffer(1 TO 80, 1 TO 25, 1 TO 2)

CLS
WIDTH 80, 25
VIEW PRINT 1 TO 25

COLOR 7, 0
COLOR 15, 1: LOCATE 1, 1: PRINT STRING$(80, " ");
LOCATE 1, 30: PRINT "Fast Windows in QBasic"
LOCATE 25, 1: PRINT STRING$(80, " ");
LOCATE 25, 18: PRINT "Press ESC to Abort/Any Other Key for New Window";

COLOR 3, 0
FOR y = 2 TO 24
   LOCATE y, 1: PRINT STRING$(80, "#");
NEXT y
COLOR 7
LOCATE 5, 5: PRINT " Notice how the background is restored. "
LOCATE 10, 25: PRINT " Notice how the background is restored. "
LOCATE 15, 5: PRINT " Notice how the background is restored. "
LOCATE 20, 25: PRINT " Notice how the background is restored. "

'*** Let's put up some random windows.
RANDOMIZE TIMER
DO
 
  x1 = INT(RND * 50) + 1
  y1 = INT(RND * 5) + 2
  x2 = INT(RND * 15) + 65
  y2 = INT(RND * 15) + 9
  fore = 15
  back = 1
  style = INT(RND * 5) + 1
  shadow = INT(RND * 2)

  '*** Store what's behind the window
  ReadBuffer x1, y1, x2, y2, buffer()

  '*** Open the window
  OpenWindow style, x1, y1, x2, y2, fore, back, 1  'shadow

  '*** Wait for a keypress
  z$ = ""
  DO WHILE z$ = ""
   z$ = INKEY$
  LOOP

  '*** Restore the background
  WriteBuffer x1, y1, x2, y2, buffer()

LOOP UNTIL z$ = CHR$(27)   '*** ESCAPE key?  If not, new window...

'******************************************
'*** OpenWindow() *** by Jonathan Leger ***
'************************************************************************
'*** I've seen some text-window routines in the All Basic Code page   ***
'*** lately that, although they did the job, they did it hideously    ***
'*** slowly.  So here's a sub that draws your windows quickly, with   ***
'*** or without a shadow (which shadows characters already on-screen) ***
'*** and with 5 styles available--see below for style info.           ***
'************************************************************************
'*** Syntax:
'***     OpenWindow style, x1, y1, x2, y2, fore, back, shadow
'***                  ^     ^   ^   ^   ^     ^     ^      ^
'***  window          |     |   |   |   |     |     |      |
'***  style # (1-5)---+     |   |   |   |     |     |      |
'***  (see below)           |   |   |   |     |     |      |
'***                        |   |   |   |     |     |      |
'***                        |   |   |   |     |     |      |
'***  top left coordinates -+---+   |   |     |     |      |
'***                                |   |     |     |      |
'***  bottom right coordinates -----+---+     |     |      |
'***                                          |     |      |
'***  foreground & background colors ---------+-----+      |
'***                                                       |
'***  use shadow (1) no shadow (0) ------------------------+
'***
SUB OpenWindow (style, x1, y1, x2, y2, fore, back, shadow)

COLOR fore, back

SELECT CASE style
   CASE 1
        'ÚÄÄÄ¿
        '³   ³
        'ÀÄÄÄÙ
        to$ = CHR$(218) + STRING$((x2 - x1) - shadow - 2, 196) + CHR$(191)
        mi$ = CHR$(179) + STRING$((x2 - x1) - shadow - 2, " ") + CHR$(179)
        bo$ = CHR$(192) + STRING$((x2 - x1) - shadow - 2, 196) + CHR$(217)
   CASE 2
        'ÉÍÍÍ»
        'º   º
        'ÈÍÍÍ¼
        to$ = CHR$(201) + STRING$((x2 - x1) - shadow - 2, 205) + CHR$(187)
        mi$ = CHR$(186) + STRING$((x2 - x1) - shadow - 2, " ") + CHR$(186)
        bo$ = CHR$(200) + STRING$((x2 - x1) - shadow - 2, 205) + CHR$(188)
   CASE 3
        'ÕÍÍÍ¸
        '³   ³
        'ÔÍÍÍ¾
        to$ = CHR$(213) + STRING$((x2 - x1) - shadow - 2, 205) + CHR$(184)
        mi$ = CHR$(179) + STRING$((x2 - x1) - shadow - 2, " ") + CHR$(179)
        bo$ = CHR$(212) + STRING$((x2 - x1) - shadow - 2, 205) + CHR$(190)
   CASE 4
        'ÖÄÄÄ·
        'º   º
        'ÓÄÄÄ½
        to$ = CHR$(214) + STRING$((x2 - x1) - shadow - 2, 196) + CHR$(183)
        mi$ = CHR$(186) + STRING$((x2 - x1) - shadow - 2, " ") + CHR$(186)
        bo$ = CHR$(211) + STRING$((x2 - x1) - shadow - 2, 196) + CHR$(189)
   CASE 5
        'ÛÛÛÛÛ
        'ÛÛÛÛÛ
        'ÛÛÛÛÛ
        to$ = STRING$((x2 - x1) - shadow, " ")
        mi$ = STRING$((x2 - x1) - shadow, " ")
        bo$ = STRING$((x2 - x1) - shadow, " ")
END SELECT

LOCATE y1, x1: PRINT to$
FOR y = (y1 + 1) TO (y2 - (1 + shadow))
   LOCATE y, x1: PRINT mi$;
   IF (y - y1) >= shadow THEN
      FOR s = 1 TO shadow
         clr = SCREEN(y, x2 - shadow + s, 1) MOD 16
         bkg = SCREEN(y, x2 - shadow + s, 1) / 16
         char$ = CHR$(SCREEN(y, x2 - shadow + s))
         IF bkg > 7 THEN
            clr = 24
         ELSE
            clr = 8
         END IF
         COLOR clr, 0
         PRINT char$;
      NEXT s
      COLOR fore, back
   END IF
NEXT y

LOCATE (y2 - shadow), x1: PRINT bo$;
FOR s = 1 TO shadow
   clr = SCREEN(y, x2 - shadow + s, 1) MOD 16
   bkg = SCREEN(y, x2 - shadow + s, 1) / 16
   char$ = CHR$(SCREEN(y, x2 - shadow + s))
   IF bkg > 7 THEN
      clr = 24
   ELSE
      clr = 8
   END IF
   COLOR clr, 0
   PRINT char$;
NEXT s
COLOR fore, back

IF shadow > 0 THEN
   FOR l = 1 TO shadow
      LOCATE (y2 - shadow + l), (x1 + shadow)
      FOR s = 1 TO (x2 - x1 - shadow)
         clr = SCREEN(y2 - shadow + l, x2 - shadow, 1) MOD 16
         bkg = SCREEN(y2 - shadow + l, x2 - shadow, 1) / 16
         char$ = CHR$(SCREEN(y2 - shadow + l, x1 + s))
         IF bkg > 7 THEN
            clr = 24
         ELSE
            clr = 8
         END IF
         COLOR clr, 0
         PRINT char$;
      NEXT s
      COLOR fore, back
   NEXT l
END IF

END SUB

'******************************************
'*** ReadBuffer() *** by Jonathan Leger ***
'******************************************
'*** Reads a block of text & color info ***
'*** off the screen to save the text    ***
'*** behind where a window is going to  ***
'*** be put.                            ***
'******************************************
SUB ReadBuffer (x1, y1, x2, y2, buffer() AS INTEGER)

'*** I used PEEKs here (and POKEs in WriteBuffer()) because
'*** they are so much faster than LOCATE and the SCREEN()
'*** function.

DEF SEG = &HB800           '*** Screen 0 segment

buf = LBOUND(buffer)
char = 1
FOR y = y1 TO y2
   FOR x = x1 TO x2
      buffer(char, buf, 1) = PEEK(((y - 1) * 160) + ((x - 1) * 2))
      buffer(char, buf, 2) = PEEK(((y - 1) * 160) + ((x - 1) * 2) - 1)
      char = char + 1
   NEXT x
   char = 1
   buf = buf + 1
NEXT y

DEF SEG                    '*** Reset to BASIC default segment

END SUB

'*******************************************
'*** WriteBuffer() *** by Jonathan Leger ***
'*******************************************
'*** Writes a block of text & color info ***
'*** onto the screen to restore the text ***
'*** behind where a window was put.      ***
'*******************************************
SUB WriteBuffer (x1, y1, x2, y2, buffer() AS INTEGER)

'*** I used POKEs here (and PEEKs in ReadBuffer()) because
'*** they are so much faster than LOCATE and the SCREEN()
'*** function.

DEF SEG = &HB800        '*** Screen 0 segment

buf = LBOUND(buffer)
char = 1
FOR y = y1 TO y2
   FOR x = x1 TO x2
      POKE ((y - 1) * 160) + ((x - 1) * 2) - 1, buffer(char, buf, 2)
      POKE ((y - 1) * 160) + ((x - 1) * 2), buffer(char, buf, 1)
      char = char + 1
   NEXT x
   buf = buf + 1
   char = 1
NEXT y

DEF SEG                 '*** Reset segment to BASIC default

END SUB
