home *** CD-ROM | disk | FTP | other *** search
- /\ RKCP /\
- \/ RKCP \/
-
- ********************************************************************
- ************************* FWIN by Rex Kerr *************************
- ************************ Copyright (C) 1989 ************************
- ********************************************************************
-
- This is a unit designed to give simple windowing capabilities to
- any program. It uses FWRITE, so it is very fast, but it also
- causes snow on snowy CGAs. It also won't autodetect EGA or VGA
- cards (another weakness of FWRITE). On top of all that, if you
- call windows in circles (i.e. you call window #1, then #2, #3, #1,
- #2, etc.) and then delete one, the image will be left on the screen,
- even though the window itself is gone. By now, I've made it sound
- horrible enough for no-one to want to use it. But it is very fast,
- and it works very well at popping up a window and then throwing it
- away after you have used it.
-
- FWIN is implemented using a circular doubly linked list. Therefore,
- you can call up any window at any time. By the way, it uses the
- standard DOS and CRT units as well as my FWRITE unit.
-
- ***
-
- FWIN's window structure is declared like this:
-
- type winptr = ^winrec;
- winrec = record
- x,y,w,h : byte; { The borders of the window }
- cx,cy : byte; { The position of the cursor }
- id : byte; { Each window has a unique ID
- number }
- wscreen : vram_scrbuf; { This is where the
- saved window goes }
- up,dn : winptr; { Pointers to the windows after
- and before this one }
- border : boolean; { Is there a border or not? }
- end;
-
- The only visible variable in the FWIN unit is the "base" of the
- window list. The current window is always one up from this.
-
- var windowset : winptr;
-
- ***
-
- GetVram(var Scrn : Vram_ScrBuf);
-
- Since FWIN often gets the whole screen, it calls this, which calls
- the GetVramSec procedure in FWRITE. It is equivalent to
-
- GetVramSec(scrn,1,1,80,25,1,1);
-
- ***
-
- PutVram(Scrn : Vram_ScrBuf);
-
- This puts all of Vram_ScrBuf on the screen. It simply calls FWRITE
- like this: PutVramSec(Scrn,1,1,80,25,1,1);
-
- It just saves some typing on your part.
-
- ***
-
- Bordermaker(a,b,c,d,e,f : byte) : string;
-
- This turns bytes a,b,c,d,e,f into characters and places them in a
- string. It is useful for making window borders with ASCII values
- above 126 or below 32.
-
- ***
-
- SetTextAttr(attr : byte);
-
- This sets the current writing attribute for Turbo Pascal's Write
- and WriteLn.
-
- ***
-
- GetXY(var x,y : byte);
-
- This calls TP5's WhereX and WhereY. It's just a time-saver.
-
- ***
-
- CreateWindow(id : byte; x,y,w,h : byte; wattr,battr : byte;
- st,border : string);
-
- Wow! What does this do?
-
- The borders of the window are x,y,w,h. Border is either an empty
- string (for no border) or the 6 chars used in the border. This is
- what the characters are used for:
- #1 : top left corner #2: top right corner
- #3 : bottom left corner #4: bottom right corner
- #5 : horizontal lines #6: vertical lines
-
- St is the string used for the "title" of the window. It is placed
- centered in the top line of the border. If there is no border, st
- is not used. Batr is the attribute used for the border, and Watr
- is the attribute used for the main text. While we're at it, here's
- at table showing the which values give which colors:
-
- COLOR FOREGROUND BACKGROUND HI-INTENSITY FOREGROUND
- Black 0 0 8 (Gray)
- Blue 1 16 9 (Light blue)
- Green 2 32 10 (Light green)
- Cyan 3 48 11 (Light cyan)
- Red 4 64 12 (Pink)
- Magenta 5 80 13 (Light magenta)
- Brown 6 96 14 (Yellow)
- White 7 112 15 (Hi-intesity white)
-
- To get the desire attribute, add the foreground color to the
- background color. For example, to get white on a black background,
- the attribute is 7. For pink on a magenta background, the
- attribute is 92. To make the foreground characters blink, add 128
- to the total.
-
- And finally, ID is the window's unique identification number. You
- use it in most of the other window routines. If you specify the ID
- number of an already existing window, nothing will happen.
-
- ***
-
- RemoveWindow(id : byte);
-
- This removes the window (specified by ID) from the linked list. It
- doesn't, however, do anything about the image on the screen. If you
- specify an ID that is non-existant, nothing will happen. You can
- check to see if a window exists or not using ExistWindow.
-
- ***
-
- GotoWindow(id : byte);
-
- This gets the specified window and puts it at the beginning of the
- linked list and updates the screen. If a non-existant ID is called,
- nothing wil happen.
-
- ***
-
- PopWindow;
-
- This removes the current window from the linked list and the screen.
- The window behind the current window now becomes the current window.
-
- ***
-
- ExistWindow(id : byte) : boolean;
-
- This returns true if a window with the specified ID exists.
- Otherwise, it returns false.
-
- ***
-
- Okay, that's everything. But I'd like to write a few extra routines
- here. With createwindow, one of the problems is it's a bit hard to
- find out which ID numbers are already existing. You could call
- existwindow from 1 until you get a false, but if you have a lot of
- windows, that could take a few lines that you might not want. So
- let's write a function that returns the first unused ID.
-
- function EmptyWindowID : byte;
- var temptr : winptr; { We need a pointer to walk through the list }
- i,j : byte; { Variables for storing the free ID }
- begin
- i := 0; j := 0; { Initialize the variables }
- while (i <> 0) do { i gets set to the free ID #. It will }
- begin { remain 0 until then. }
- inc(j); { j is the counter for possible open windows }
- temptr := windowset^.up; { temptr is pointing to the
- current window }
- while (temptr <> windowset) and (temptr^.id <> j) do
- begin { If temptr's ID = j or temptr has cirled the list, STOP }
- nptr := nptr^.up; { Go up to the next window }
- end;
- if nptr = windowset then i := j; { If temptr has circled, }
- end; { that ID is free, so set i }
- EmptyWindowID := i; { give the function the result }
- end;
-
- What this does is it circles through the linked list to see if
- any of the windows have an ID of 1. If none do, i is set to one.
- Otherwise, the same thing is done for 2 and 3 and 4 etc. until
- a "free" ID is found. Then the function is set to the value of i
- (the free ID number).
-
- That wasn't so hard. Now, let's do something else. How about this:
- The screen has gotten rather cluttered up, and you want to clean it
- up. How do you do that? Why don't we write a procedure to do that
- for us.
-
- procedure CleanUpScreen;
- var temptr : winptr;
- i : byte;
- begin
- i := EmptyWindowID;
- createwindow(i,1,1,80,25,7,7,'','');
- temptr := windowset^.dn;
- while temptr <> windowset do
- begin
- if temptr^.id <> i then gotowindow(temptr^.id);
- end;
- removewindow(i);
- end;
-
- I didn't include any comments on purpose. I'm going to let you
- figure out what each line does. That is, in my opinion, the second
- best way to learn how to program (assuming you know the basics). I
- think the best way is just to program and program and program
- whatever yourself. Most of my programming so far has been in the
- realm of useless. I have scores of tiny programs that do everything
- from create random beeps to copy one file half as fast as DOS
- would. But I have gotten lots of experience from that, and now I
- can quickly whip up a simple program when I need it. One example
- is this: I had a list of books read and how many pages were in
- each one. I was supposed to add the pages to get the total and
- check to make sure there was only one entry for each book. So
- in about fifteen or twenty minutes, I had written a program that
- did just that. Then, I spent another fifteen minutes entering the
- list into the computer (the list was on paper). So, in roughly
- 35 minutes, I did a job which, without any programming, would have
- taken maybe 40 minutes. Big deal. I saved 5 minutes. But now I
- have the program, and it I'm most likely going to have to do that
- again, so overall, I could end up saving myself hours. So now, all
- that experience with writing all those tiny programs is starting to
- pay off.
-
- Whoa! I thought I was supposed to be writing documentation for
- FWIN! Okay, back to that now.
-
- I will give you a bit of help in understanding what the
- CleanUpScreen procedure does. First it calls EmptyWindowID to find
- an unused ID. Then it creates a big blank window to clear the
- screen. After that, it starts at the back of the list, calling
- each window until it arrives at the "base" to rebuild the screen.
- Along the way, it makes sure to skip the blank window, so the work
- won't be wasted. Then, after the screen has been cleared and
- updated, it removes the blank window from memory, and quits.
-
- I also have a second windowing unit, XWIN. XWIN is slower than
- FWIN is, but it doesn't have the "junk" problem. XWIN's
- popwindows can be up to 10 times slower than FWIN's, but with
- XWIN you never need the CleanUpScreen procedure. Actually, if
- FWIN calls CleanUpScreen after each popwindow to make sure the
- screen doesn't have any inactive windows, XWIN is much faster. Also,
- FWIN takes 4 kbytes of heap for each window, whether the window is
- 5*4 or 80*25. XWIN takes up a 22 bytes plus the amount of memory
- required to hold just the window. Here's a formula to calculate
- that amount of memory:
-
- mem_required := (window_width * window_height) * 2;
-
- But you don't have to worry about calculating the memory; XWIN does
- it for you.
-
- I prefer using XWIN, but FWIN can still be useful.
-
- If you think I've left anything out, or if anything is unclear,
- please contact me via Compuserve, using either EasyPlex or the
- TP5 messages section of BPROGA.
-
- Rex Kerr 71550,3147
-
- /\ RKCP /\
- \/ RKCP \/