
                                 PASCAL MAGIC

               (c) Copyright 1992, Jeff Napier & Another Company


                                 Tutorial File


         What Pascal Magic can do for you:

            This  disk  consists  of three parts, Magic.Tpu, Magic.Doc
         and  Tutorial.Txt. Magic.Tpu is an add-in for Borland's Turbo
         Pascal version 6.0 which will make your job as  a  programmer
         much easier and your results much more polished. Magic.Doc is
         a  text  file  which  explains how to use all the features of
         Magic.Tpu, and Magic.Tut, the file you are now reading, is  a
         tutorial  which starts at a very beginning level and quickly,
         but effortlessly moves into advanced programming techniques.

         Specifically, Magic.Tpu offers the following:

         *  Automatic  pop-up  text  boxes, dialog boxes and light-bar
         menus.

         * Automatic handling of text files.

         * Built-in mouse support for the programs you create.

         * Support for graphics programs to make them as easy to write
         as text-based programs.

         * Incorporation of .BGI and .CHR files directly into finished
         .EXE files.

         * Sound effects for your programs.

         * Simplification of many Turbo Pascal operations.

         * Complete color control in text and graphics modes.

         * Build cursor control into  your  programs  for  laptop  LCD
         screens.

         *   Full,   documented,  easy-to-understand  source  code  is
         available  so  you  can  learn  from  and customize the Magic
         framework to your own applications.

                                     NOTE:

            This  is  a  shareware  product.   You  have  our specific
         permission to copy and distribute this package as long as all
         files remain intact and unchanged.
            If  you  benefit  from  this  tutorial,  or if you use the
         Magic.Tpu unit in your programs you are expected to register.
         To register, send $29.95 to:

                                Another Company
                                 P.O. Box 298
                              Applegate, OR 97530
                                      USA

         If  you  would  like  the  full   source   code   with   your
         registration, send $59.90. Please specify disk size.

                                  QUESTIONS:

         If you have questions: 503-846-7884, 9-5 Weekdays, West Coast
         time. (We are not always available during those hours.)

                      THE BEST WAY TO USE THIS TUTORIAL:

         Copy  Magic.Tpu  to  the directory where you keep your Pascal
         *.tpu files, and copy Tutorial.txt  to  the  directory  which
         contains  your  *.pas files. Start your Turbo.Exe and load in
         this file, (type: TURBO TUTORIAL.TXT). Since the Turbo Pascal
         IDE  (Integrated  Development Environment) allows you to work
         on several files at once, you can read this tutorial  in  one
         window  and  work on practice programs in another window.  If
         you don't know how  yet,  I'll  show  you.   If  you  are  an
         experienced  programmer,  you might want to skip through this
         tutorial and concentrate only on the areas that  are  new  to
         you.

                           A COUPLE OF OTHER NOTES:

         1. It is assumed that you have legally purchased Turbo Pascal
         version  6.0  and  therefore  have  the four valuable printed
         manuals that come with the program. If not, you  are  advised
         to  go  spend  a  little money and get what you need, because
         there are places within this tutorial which will refer you to
         those books to complete your knowledge.

         2. This is not the last word  on  Turbo  Pascal.  It  doesn't
         teach  everything  about  programming  - probably not even 10
         percent of what you will eventually learn, but  between  this
         tutorial  and  the Borland manuals, you'll get pretty good at
         programming, and fairly quickly. One  of  the  best  ways  to
         learn  this  is  to  experiment  frequently. Tear the example
         programs apart and try to interject your own ideas into them.
         See what you can change or improve, then run the programs you
         have modified and see what happens. As  you  well  know,  you
         can't hurt your computer by typing an incorrect line of code.

         3.  Turbo  Pascal is not sensitive to capitalization or white
         space. The exact placement of indentations is  not  important
         and  every programmer develops a slightly different style. In
         this tutorial, I have  tried  to  capitalize  letters  within
         procedure  and  function  names where such capitalization may
         make the source code easier to read. This 'convention' occurs
         irregularly throughout this tutorial.

         4. This is version 1.0 of  what  I  believe  is  a  wonderful
         product,  but  then, I wrote it.  Let me know what you think.
         I'm pretty sure I caught all the major bugs, but there may be
         some minor ones. Most likely the registered and/or subsequent
         shareware versions will be even better!

         5.  To use Magic.tpu, Video.tpu and Fonts.tpu will also  need
         to  be  available in the same sub-directory. Also, Graph.tpu,
         furnished with Turbo Pascal must be in the sub-directory.


                                  HERE WE GO:

         Here is the simplest program you can write:

              begin
              end.

         Let's try it out. Press  [F3].  (First  finish  reading  this
         paragraph  so  you  know  how  to get back.) A window pops up
         asking for a file name.  Call  it  Prog1  (or  any  name  you
         choose)  and  type  the  preceding  two-line  program.  Don't
         forget the period after end. In Pascal, there is no  need  to
         care about capitalization, Capitals, small case or mixed-case
         makes  no  difference.  Press [F2] to save your valuable work
         against power failure, etc. While  holding  the  [Ctrl]  key,
         press  [F9]  and  the program will run. Did you blink? Since,
         the program  doesn't  actually  do  anything,  it  runs  very
         quickly,  then returns to Turbo Pascal. To switch back to the
         first window, press [Alt] and [1].

         This next program is just  like  the  first,  it  doesn't  do
         anything,  but  it is also a legal program. There is one more
         line starting with the word Program. Some versions of  Pascal
         require this line, but with Turbo Pascal, it is optional.

              program prog2;
              begin
              end.

         Next,  we'll add something to the program so it will actually
         have a purpose:

              program prog3;
              begin
                 write('Hello, World!');
              end.

         This program only  does  one  thing,  it  "write"s  the  text
         between  the  single quote marks to the screen. Turbo Pascal,
         like all computer applications is sensitive to exact spelling
         and punctuation. Make sure you have a colon at the end of the
         write('Hello, World!'); line, and that all the  other  pieces
         are in their proper places.
             Go  ahead  and  run  this program. Press [Alt] and [2] to
         get back to the other window you opened, and add the lines to
         make the first program into this one. Or, if  you  wish,  you
         can  make  a block around this prog3, using the mouse or with
         ^KB the arrow keys ^KK, (actually there are several  ways  to
         mark  a block). Then press [Alt] and [E], then [C]. This puts
         a copy of the marked block in  the  Turbo  Pascal  clipboard.
         Switch  to  the  other  window (use [Alt]-[2], or [Alt]- [W],
         [L]). Then press [Alt]-[E], then [P] to paste the block  into
         the  second  window. Erase the previous program, then compile
         and run the new prog3.
             It happened very quickly, didn't it? Lets slow it down in
         prog4:

              program prog4;
              begin
                 write('Hello, World!');
                 readln;
              end.

         In prog4, the line readln causes the computer to wait for the
         user to press the [Enter] key.  Now  you  can  take  time  to
         contemplate your "Hello, World!" line.
             You  may  notice  that the screen wasn't cleared of other
         junk when prog4 ran. In prog5, let's clear the screen, giving
         the  "Hello,  World!"  line  more  clarity.  We'll  use   the
         procedure  clrscr,  which  Turbo Pascal provides to clear the
         screen.

              program prog5;
              begin
                 clrscr;
                 write('Hello, World!');
                 readln;
              end.

         What happened? If you tried to run this program, you'll  have
         noticed  that it didn't work. Turbo Pascal does not recognize
         "clrscr." Did I misspell it?  No.  I  didn't  tell  you  that
         clrscr is not part of Turbo Pascal itself. It is in a library
         of operations for screen handling called Crt.
            Turbo  Pascal  provides  5  special libraries of routines,
         called units. They are Crt,  System,  Printer,  Printer,  and
         Dos.  You  can  also  create  your  own  custom units, or buy
         special units from programmers.
            These 5 are special because they are grouped together in a
         special file called Turbo.Tpl, but usually units are separate
         files  with the extension of .Tpu. The corrected prog5a shows
         how to use a unit:

              program prog5a;
              uses crt;
              begin
                 clrscr;
                 write('Hello, World!');
                 readln;
              end.

         As the proper prog5 indicates,  to  use  something  within  a
         unit,  simply  declare  the  unit's  name in the "uses" line,
         which you must type just below the "program" line, or as  the
         first  line  in  the program.

         Let's get a bit fancier, take a look at prog6.

              program prog6;
              uses crt,magic;
              begin
                sent[1] := 'Hello, World!';
                GetAnyKey(5,11);
              end.

         Prog6 uses the Magic.Tpu unit. Give this program a try.  Kind
         of  prettier,  isn't  it?  Let's  talk about prog6 in detail.
         You'll  notice  that  instead  of  writing  "Hello,   World!"
         directly  to  the  screen,  we  have  assigned that string of
         characters to a variable called "sent[1]." In the magic unit,
         "sent" is an array of sentences called strings. An array is a
         group of something, all of which are the same type and  size.
         The  "sent" array is 46 strings, each of which can contain up
         to 76 characters. In prog6, we have used only  one  of  them,
         the first one, number [1]. When you want to specify a certain
         item  from  an  array  of items, you put its number in square
         brackets. Until sent[1] was told to equal with  ":="  (called
         "assignment  equals")  "Hello, World!," it was nothing. Until
         prog6 assigned "Hello, World!" to it, sent[1]  was  equal  to
         nothing,  like  this:  sent[1]  := ''. In fact, all the other
         sent[]s in prog6 are still nothing. The magic unit  will  use
         only the sent[]s which contain data.
            The  next  line,  "GetAnyKey(5,11)" calls a procedure that
         displays the  sent[]s  which  contain  data  in  a  bordered,
         shadowed  box,  and  waits  for  the user to press any key or
         click a mouse button. The two numbers following GetAnyKey are
         coordinates. These refer to the position on the screen  where
         the  box is to pop up. Specifically, they mark the upper left
         corner of the pop-up box.
            The first number is the horizontal position on the screen.
         If  it  were  1,  then the box would be jammed up against the
         left  hand edge of the screen. 80 is the right-hand edge of a
         standard text screen since it is 80 characters wide, but  you
         can't  put  the  left edge of a text box there if you want to
         see it.
            The  second number is, of course, the vertical coordinate,
         with 1 being the top of the screen and 25 being the bottom.
            You'll notice, that clrscr is missing. It  is  not  needed
         with  the magic unit, since the unit automatically clears the
         screen when the program starts. But, I left "Crt" in the uses
         statement. This is easy programming practice, because if  you
         don't  use  anything from the Crt unit, Turbo Pascal does not
         increase the size of the compiled program. Yet, if  you  need
         something  from  the unit, it is at your disposal. You'll see
         that many of my programs "use" the Crt unit, even though they
         don't end up using anything in the Crt unit.

         Prog7 illustrates a close relative to GetAnyKey, GetYN. While
         GetAnyKey waits for the user to press almost anything,  GetYN
         stalls  the  program  until  the  user presses [Y] or [N], or
         clicks the left or right mouse button. Also, you'll note that
         one  of  the  coordinates  is  a  negative  number.  In   the
         preceding  paragraphs,  you'll notice  I didn't allow for the
         possibility of a negative screen coordinate, and  technically
         there is no such thing.  When the magic unit comes  across  a
         negative  coordinate, it ignores the number and automatically
         figures out where the center of the screen is and pops up its
         box there!  In other words, if you pass a negative number for
         the vertical location, the box will be between  the  top  and
         bottom  of  the  screen. If you use a negative number for the
         horzontal location, the box will be centered right to left on
         the screen.

              program prog7;
              uses crt, magic;
              begin
                sent[1] := 'Do you want to quit? (Y/N)';
                sent[2] := '';
                sent[3] := 'This is just a test, actually, the program';
                sent[4] := 'is gonna quit whether you answer Y or N';
                GetYN(-5,3);
              end.

         Let's make a slight improvement in the  next  program.  Prog8
         changes  a  boolean variable, declared from the magic unit. A
         boolean is a variable which can have only two values, true or
         false. This particular variable is  CenterJustify.  Normally,
         it is false (the "default" condition) but if changed to true,
         then  the  strings  in the sent array will be centered within
         any pop-up box. Run prog8 and you'll see what I mean.

              program prog8;
              uses crt, magic;
              begin
                sent[1] := 'Do you want to quit? (Y/N)';
                sent[2] := '';
                sent[3] := 'This is just a test, actually, the program';
                sent[4] := 'is gonna quit whether you answer Y or N';
                CenterJustify := true;
                GetYN(-5,3);
              end.

         Prog8 is a little prettier, n'est ce pas? Prog9 will walk its
         talk, it won't end until the user says "yes" by pressing [Y].
         It uses  a  repeat  loop,  which  simply  repeats  everything
         between  the  words  "repeat" and "until" until the condition
         listed after "until" is true. GetAnyKey and  GetYN  wait  for
         the  user  to  press  a  key. The difference is that GetYN is
         specific, it waits for the key pressed  to  be  'Y'  or  'N'.
         Both  of  these  procedures  assign  the character of the key
         pressed to a global character variable  called  U.  So,  when
         GetAnyKey or GetYN are done, u becomes what the user pressed.
         In  the  special  case  of GetYN, if the user pressed a small
         case 'y' or 'n', it is automatically converted into a capital
         letter. Furthermore, GetYN makes u := 'Y' if the  left  mouse
         button  was  clicked,  and u := 'N' if the right mouse button
         was clicked.

              program prog9;
              uses crt, magic;
              begin
                repeat
                   sent[1] := 'Do you want to quit? (Y/N)';
                   GetYN(-5,3);
                until u = 'Y';
              end.

         Prog10 introduces a new magic procedure called  Dialog.  With
         this,  you  can  pose  a  question, and have the user type an
         answer. Try it.

              program prog10;
              uses crt, magic;
              begin
                 sent[1] := 'How would you answer this question?';
                 Dialog(-1,-1);
                 sent[1] := 'User typed:';
                 sent[2] := Answer;
                 GetAnyKey(-1,-1);
              end.

         Prog10 allows the user to  type  the  answer,  then  if  your
         program  were  more  sophisticated  that  prog10,  you  could
         process that answer.  The answer is contained in  the  global
         string  variable  Answer  which GetAnyKey uses to display the
         result. Notice  that  "User  typed:"  is  in  single  quotes,
         telling  GetAnyKey  to type literally that, but Answer is not
         in quotes, telling it to print the string represented by  the
         variable answer, and not type "Answer".

             In  prog10,  you  could  make  the  whole  operation more
         evident if you used some color control. Try prog11.

              program prog11;
              uses crt, magic;
              begin
                 sent[1] := 'How would you answer this question?';
                 Dialog(-1,-1);
                 BoxBack := White;
                 Border := LightBlue;
                 BoxText := Green;
                 Shadow := Magenta;
                 sent[1] := 'User typed:';
                 sent[2] := Answer;
                 GetAnyKey(-1,-1);
              end.

         Prog11 is ugly, but you can see  how  to  change  the  colors
         within  the text box. The colors seem to be used here as some
         sort  of  variables  and  they  are.  They  are   pre-defined
         constants  from  the  Turbo Pascal Crt unit.  The Box colors,
         Border, and Shadow are global variables from the magic unit.
              The Colors could just as easily have been represented by
         numbers, as in the following example:

              program prog11a;
              uses crt, magic;
              begin
                 sent[1] := 'How would you answer this question?';
                 Dialog(-1,-1);
                 BoxBack := 15;
                 Border := 9;
                 BoxText := 2;
                 Shadow := 5;
                 sent[1] := 'User typed:';
                 sent[2] := Answer;
                 GetAnyKey(-1,-1);
              end.

         Lets find out what all the colors are:  Here  is  a  slightly
         more complex program than any we have made so far:

              program prog12;
              uses crt, magic;
              begin
                 border := white;
                 BoxBack := black;
                 CenterJustify := true;
                 sent[1] := 'Type a number from 0 to 15.';
                 dialog(-1,-1);
                 repeat
                    BoxText := number;
                    if (BoxText  < 1) or (BoxText > 15) then boxtext := 15;
                    sent[1] := 'The current color is #' + answer;
                    sent[2] := 'Type a number from 0 to 15';
                    sent[3] := 'or type 16 to exit';
                    dialog(-1,-1);
                 until answer = '16';
              end.

         In  detail, prog12 does this: First, the Border color and the
         BoxBack color are changed. CenterJustify will center text  in
         the pop up boxes.
            Then  a  one-line  dialog box appears. As soon as the user
         answers the question in  this  dialog  box,  a  repeat  loop,
         starts.  The  repeat  loop  changes  the BoxText color to the
         "number" corresponding to what the user typed in  the  dialog
         box.  "Number"  is  a function from the magic unit.  It takes
         the Answer string (as returned by  Dialog)  and  converts  it
         from  a  string  into an integer variable. That way it can be
         assigned to BoxText and BoxText will be able to handle it.
            Since  the only 'seeable' colors range from 1 to 15 (#0 is
         black),  the  line  starting  with  'if'  repairs the boxtext
         number if it not suitable.
            BoxText is a byte variable (only values it can handle  are
         0  through 255), but Answer is a string. Number fixes that by
         becoming a integer compatible with BoxText.
            Within the repeat loop a new box pops up containing  three
         lines  of  text  written  in  the  color corresponding to the
         number the user typed in the dialog box.
            This all repeats until the user types "16".

         Let's make that program a little cleaner:

              program prog13;
              uses crt, magic;
              begin
                 border := white;
                 BoxBack := black;
                 CenterJustify := true;
                 sent[1] := 'Type a number from 0 to 15.';
                 dialog(-1,-1);
                 repeat
                    BoxText := number;
                    if (BoxText  < 1) or (BoxText > 15) then boxtext := 15;
                    sent[1] := 'The current color is #' + answer;
                    sent[2] := 'Type a number from 0 to 15';
                    sent[3] := 'or type 16 to exit';
                    dialog(-1,-1);
                 until (answer = '16') or (u = #27);
              end.

         There is only  one  small  change.  Can  you  spot  it?   The
         second-from  last line now allows the user out of the loop by
         typing "16" or by pressing the [Esc] key which is Ascii  #27.
         This  is  because Dialog uses the global character u to build
         the Answer string. U always contains the character  value  of
         the last character entered, which in the case of pressing the
         [Esc] key would be #27.

         Prog14  will  be our first program that does something useful
         in the real world.  It will produce the square of an integer.
         I know  that's  not  much.  You  paid  around  $1000 for your
         computer, but your $5  calculator can do  squares, and it can
         even do it  with  floating  point numbers, which this example
         can't.  The  importang thing is, once you learn this, you can
         build on this program.

              program prog14;
              uses crt, magic;
              var
                 thing : word;
              begin
                 repeat
                    sent[1] := 'Type a number to be squared';
                    sent[2] := 'or press [Esc] to end program';
                    dialog(3,3);
                    if u <> #27 then
                    begin
                       thing := number * number;
                       str(thing,answer);
                       sent[1] := 'The square is ' + answer;
                       GetAnyKey(40,15);
                       XClear;
                    end;
                 until (u = #27);
              end.

         Prog14 introduces two new concepts. First we have a line that
         contains  "var." This line is found before the first begin in
         any procedure, or before the body of a program but after  the
         uses  clause. The lines that follow "var" are "user-declared"
         variables. If they are declared before the main body  of  the
         program they are "global," usable throughout the program.  If
         they  are  declared  within a function or procedure, they are
         usable only by that function or procedure.
            In this case, we have declared, "thing  :  word."  on  the
         left  of  the  colon (notice no = sign) is any combination of
         letters and numbers and "_"  allowed  by  Turbo  Pascal  (see
         manual). On the right of the colon is the type of variable it
         is.  A  word is a integer number with a positive value from 0
         to approximately 64000. Other common types appointed by Turbo
         Pascal are integer (approx  value  -32000  to  +32000),  real
         (floating  point  number),  byte  (0 to 255), char (Any ASCII
         character),  string  (an  array,  or  group  of  characters),
         pointer  (indicating  the  starting location of a variable of
         any type stored in memory) and an array (a group  of  any  of
         these  items).  Additionally, you can make up your own types,
         composed of one or more of these basic types  in  a  mixture.
         For more information about all this, watch the Var section of
         the  programs  that  follow  in  this  tutorial, and see your
         Borland manuals.
             Furthermore, we  introduced  "str"  which  is  a  Borland
         procedure  to  convert  a  numeric  variable  into  a  string
         representing that number in text.
             This program is easy to crash. All  you  have  to  do  is
         pick  a  number  that's  square  is  more than the range of a
         "word" type variable. (64000)
             There are a couple more new things here, but if  you  are
         sharp,  you  probably already picked them out. One is the "*"
         which is computer programming talk for "multiply". The  other
         is the "<>" which means "not equal to."
             This  program will be quite confusing, it would have been
         confusing to me for the first year or so  that  I  was  using
         Turbo  Pascal,  so you might want to study it carefully. Once
         you understand what everything does, try making  changes  and
         see  if the do what you would expect. Once you get it, you're
         well on your way to writing custom programs.

             Most of prog15 is similar to the last, but  this  one  is
         for converting inches to millimeters. Try it and you'll see a
         surprise.

              program prog15;
              uses crt, magic;
              var
                 millimeters : real;
              begin
                 repeat
                    sent[1] := 'Enter a number of inches';
                    sent[2] := 'or press [Esc] when done';
                    dialog(2,2);
                    if u <> #27 then
                    begin
                       millimeters := number * 25.4;
                       str(millimeters,answer);
                       sent[1] := 'That would be ' + answer + ' millimeters';
                       GetAnyKey(30,20);
                       xclear;
                    end;
                 until u = #27;
              end.

              The  surprise  is  in  the way Turbo Pascal handles real
         variables when converted to string variables. Unless you  add
         specific formatting commands, you'll get scientific notation.
         So,   prog15a  has  a  small  change  in  the  str  procedure
         parameters,  specifically,  "millimeters"  is  followed  with
         ":1:0."  See  your  Borland  books  for more information, but
         basically, if the first integer is anything less than 8, then
         up  to  8  digits  will  be  displayed.  The  second  integer
         determines  how  many  digits after the decimal point will be
         considered in the string. For monetary notations, your second
         integer would typically be 2, for cents.

              program prog15a;
              uses crt, magic;
              var
                 millimeters : real;
              begin
                 repeat
                    sent[1] := 'Enter a number of inches';
                    sent[2] := 'or press [Esc] when done';
                    dialog(2,2);
                    if u <> #27 then
                    begin
                       millimeters := number * 25.4;
                       str(millimeters:1:0,answer);
                       sent[1] := 'That would be ' + answer
                          + ' millimeters';
                       GetAnyKey(30,20);
                       xclear;
                    end;
                 until u = #27;
              end.

              Program 16 converts Dupers from the country  Xanopieland
         to United States Dollars.

              program prog16;
              uses crt, magic;
              var
                 dollars : real;
              begin
                 centerjustify := true;
                 sent[1] := 'How many Dupers?';
                 dialog(-1,-1);
                 dollars := number * 0.7143; {current duper
                                             conversion rate}
                 str(dollars:1:2,answer);
                 sent[3] := '$' + answer;
                 sent[2] := '';
                 sent[1] := 'You own this much Xanopieland money:';

                   (* notice that sent[3] is assigned above *)

                 sent[4] := '';
                 sent[5] := 'Press any key to end program...';
                 GetAnyKey(-1,-1);
              end.

         Prog16 introduces comments. There are two ways  you  can  put
         comments into your source code that won't affect the way your
         program  is  compiled.  One  is  to  place  it  between curly
         brackets {} and the other way is to use  (*  and  *)  as  the
         borders  of  comments. Comments can extend over several lines
         as long as the beginning is marked with { or (* and  the  end
         is  marked  with  the matching } or *). You can even nest one
         type within another:
                       {comment (* within a comment *)}
             No  matter how many comments you put in your source code,
         there will be no change in the compiled program's size or run
         time speed.
             Comments can be very important for you or for others that
         have to figure out your programs a long time after  you  have
         created them.
             Prog16  also  illustrates that Turbo Pascal is not at all
         fussy about white space. The only place white  space  matters
         is within strings. The same program can be written this way:

         program prog16a; uses crt, magic; var dollars : real; begin
         centerjustify := true; sent[1] := 'How many Dupers?';
         dialog(-1,1); dollars := number * 0.7143; {current duper}
         {conversion rate} str(dollars:1:2,answer); sent[3] := '$' +
         answer; sent[2] := ''; sent[1] :=
         'You own this much Xanopieland money:'; (* notice that
         sent[3] is assigned above *) sent[4] := ''; sent[5] :=
         'Press any key to end program...'; GetAnyKey(-1,1); end.

         Program 16a is just as easy for the  compiler  to  read,  but
         much harder for humans to read!

         Let's  make one more improvement in prog16. In prog16b, we'll
         straighten out the way Dupers can be  entered.  The  standard
         dialog  box is as wide as the widest sent[] and therefore the
         answer can be that long. What if you want to limit  the  user
         to  a  4-digit  answer, for instance? The following technique
         works well for use with filling in database forms:

              program prog16b;
              uses crt, magic;
              var
                 dollars : real;
              begin
                 centerjustify := true;
                 sent[1] := 'How many Dupers?';
                 sent[2] := ' '; {must be at least one char}
                 pop(-1,-1);
                 textcolor(BoxText);
                 textbackground(BoxBack);
                 answer := XReadLn(38,12,4);
                 restore;
                 dollars := number * 0.7143;
                 str(dollars:1:2,answer);
                 sent[3] := '$' + answer;
                 sent[2] := '';
                 sent[1] := 'You own this much Xanopieland money:';
                 sent[4] := '';
                 sent[5] := 'Press any key to end program...';
                 GetAnyKey(-1,-1);
              end.

         Can you spot the differences? This program does not depend on
         Dialog.  Instead,  we  pop  up  a  box with "pop," which is a
         simple procedure that remembers what's on  the  screen,  then
         puts  a  box  on  the screen. Since pop will use only as many
         sent[]s as have text, sent[2] is ' ', or  one  blank,  so  it
         will  be  included  in  pop's box.  This will give the user a
         line within the box on which to type the answer.
            Then  the  current text color and background color are set
         to the same as the colors within the box,  so  that  XReadLn,
         will  work  in  the  proper colors. XReadln is like the Turbo
         Pascal ReadLn procedure but with three  differences.  XReadLn
         accepts  mouse  control  (left  mouse button is like pressing
         [Enter] and right button is like [Esc]), XReadLn requires two
         integers to designate the screen coordinates at which it will
         echo the text typed by the user, and a  third  integer  which
         limits how long a string the user is allowed to type.
             Dialog  knows  when  the  user  is done, and restores the
         screen and disappears, but pop doesn't know what  is  wanted,
         so  stays  on  the  screen  until a specific call to Restore,
         which wipes it out and replaces the previous screen image.

         Prog17 shows many new techniques. It is the  Universal  Money
         Converter.  For  simplicity,  only the first menu entry has a
         procedure installed. Run this program to see  what  it  does,
         then  study  the  source  code  to see how it does it. From a
         practical point of view, you can see that with modifications,
         this could be used for real money from  real  countries.  For
         that  matter,  the  same  program  could be modified for many
         purposes.  How  about  a  universal  metric  converter   that
         converts lengths, weights, temperatures, etc?
            (NOTE:  When  I  first roughed out this tutorial, I got to
         thinking about the previous sentence, and an idea  was  born.
         It  is  now  complete  and  being  distributed  as shareware.
         Perhaps you've seen it, THE  UNIVERSAL  CONVERTER.  This  new
         program  performs  over  600 useful calculations and it makes
         extensive use of Pascal Magic!)

              program prog17;
              uses crt, magic;
              var
                 dollars : real;

              procedure xano;
              begin
                 sent[1] := 'How many Xanopieland Dupers?';
                 sent[2] := ' '; {must be at least one char}
                 pop(-1,-1);
                 textcolor(BoxText);
                 textbackground(BoxBack);
                 answer := XReadLn(38,12,4);
                 restore;
                 dollars := number * 0.7143;
                 str(dollars:1:2,answer);
                 sent[3] := '$' + answer;
                 sent[2] := '';
                 sent[1] := 'You own this much Xanopieland money:';
                 sent[4] := '';
                 sent[5] := 'Press any key to continue...';
                 GetAnyKey(-1,-1);
              end;

              begin  {main}
                 centerjustify := true;
                 sent[1] := 'Universal Money Converter';
                 pop(25,2);
                 mc := 1;
                 repeat
                    sent[1] := 'Xanopieland';
                    sent[2] := 'Braze Island';
                    sent[3] := 'Nomania';
                    sent[4] := 'Grazille';
                    sent[5] := 'Exit to Dos';
                    menu(-1,-1);
                    if u = #13 then
                    begin
                       if mc = 1 then xano;

                   (*  if mc = 2 then braze;
                       if mc = 3 then nomania;
                       if mc = 4 then Grazille; *)
                     end;
                 until (u = #13) and (mc = 5);
                 CleanUp;
              end.

         The most noticeable change  is  the  use  of  a  sub-routine,
         called  a  "procedure."  And Pascal seems kind of backward at
         first - the main program is the bottom-most  thing,  and  the
         procedure(s)  are at the top. In Pascal, it must be this way.
         Any  procedure  or  function  that  is  called  from  another
         procedure  or  function,  or  from  the main program, must be
         above  it in the source code. Actually, there are ways around
         this (see Forward declaration in your Borland  manuals),  but
         for now, we'll keep it simple.
            The procedure Xano is called only when  the  user  selects
         the first menu entry.
            Now, let's look at the main program to see exactly what it
         does.  You  know  CenterJustify.  It  makes  all  the sent[]s
         centered within the pop-up boxes.
            Then a box pops near the top of the screen with the  text,
         "Universal  Money  Converter." Then we have a funny line, "mc
         := 1." I'll explain that one in a minute.
            Within the repeat loop are 5 sent[]s and  a  call  to  the
         magic  procedure  "menu". Menu is like the other pop-up boxes
         you are familiar with, but it is a light-bar menu. It  allows
         the  user  to  highlight any one of the sent[]s by moving the
         mouse or using the arrow keys. When the user presses [Enter],
         [Esc] or a mouse button, the menu box  disappears.  A  global
         integer  variable,  "mc" is assigned the number of the sent[]
         that was highlighted when the menu box disappears. So if  the
         user has highlighted Nomania (sent[3]), then pressed [Enter],
         then mc will equal 3.
            And  after  the menu box disappears, the next line of code
         will be executed, which happens to be "if mc = 1 then  xano."
         Well,  if the user selected Nomania, then mc is not 1 and the
         procedure xano will not be run. mc = 3, but the line, "if  mc
         =  3  then  nomania" is commented out, so nothing will occur.
         However, if the user had selected Xanopieland, then mc  would
         be  1  and the procedure xano would be executed. And you know
         what that does, it is the same as prog16. If the user  should
         select  sent[5]  then  mc will be 5 and the until clause will
         then allow the program to end.  The  last  procedure  in  the
         program  is  CleanUp  which restores everything to the way it
         was before the program started. It resets the screen  colors,
         clears  the  screen  and  the  program terminates gracefully.
         CleanUp should be used at the end of every program. It has  a
         very  specific purpose here. Remember the one-line pop at the
         beginning of the program? It held a picture of  what's  under
         that  box  in  memory  and  is still holding it until calling
         CleanUp. We never "Restore"d the first "pop".
             Now about that line "mc := 1." Without  this  line,  when
         menu  is  first  started,  it  doesn't  know  which sent[] to
         highlight. You must tell it. If you forget to assign a  value
         to  mc  before  calling  a  menu,  then a random item will be
         highlighted. Notice that "mc := 1" is before the repeat loop.
         This is because, once the repeat loop starts, the user may be
         most comfortable seeing the menu pop-up  with  the  highlight
         where  it  was last located rather than on the top item every
         time.

         Prog18 is the same as the last one, except we use  DoubleMenu
         instead  of  Menu.  Everything  is  the same, but the menu is
         shorter and wider, allowing for situations where you may have
         lots of menu choices. You can  use  up  to  36  sent[]s  with
         DoubleMenu.

              program prog18;
              uses crt, magic;
              var
                 dollars : real;

              procedure xano;
              begin
                 sent[1] := 'How many Xanopieland Dupers?';
                 sent[2] := ' '; {must be at least one char}
                 pop(-1,-1);
                 textcolor(BoxText);
                 textbackground(BoxBack);
                 answer := XReadLn(38,12,4);
                 restore;
                 dollars := number * 0.7143;
                 str(dollars:1:2,answer);
                 sent[3] := '$' + answer;
                 sent[2] := '';
                 sent[1] := 'You own this much Xanopieland money:';
                 sent[4] := '';
                 sent[5] := 'Press any key to continue...';
                 GetAnyKey(-1,-1);
              end;

              begin  {main}
                 centerjustify := true;
                 sent[1] := 'Universal Money Converter';
                 pop(25,2);
                 mc := 1;
                 repeat
                    sent[1] := 'Xanopieland';
                    sent[2] := 'Braze Island';
                    sent[3] := 'Nomania';
                    sent[4] := 'Grazille';
                    sent[5] := 'Exit to Dos';
                    doublemenu(-1,-1);
                    if u = #13 then case mc of
                       1 : xano;
                    (* 2 : brace;
                       3 : nomania;
                       4 : grazille; *)
                    end;
                 until (u = #13) and (mc = 5);
              end.

         In  prog18 we have also cleaned up the multiple if statements
         by  using  a  "case"  statement.  But,  there  are  still  no
         procedures  written for 3 of the 5 menu choices, so these are
         commented out.

         Prog19 adds another  case  statement  allowing  the  user  to
         press  a key corresponding to the first letter of a menu item
         and then that procedure will be run directly.

              program prog19;
              uses crt, magic;
              var
                 dollars : real;

              procedure xano;
              begin
                 sent[1] := 'How many Xanopieland Dupers?';
                 sent[2] := ' '; {must be at least one char}
                 pop(-1,-1);
                 textcolor(BoxText);
                 textbackground(BoxBack);
                 answer := XReadLn(38,12,4);
                 restore;
                 dollars := number * 0.7143;
                 str(dollars:1:2,answer);
                 sent[3] := '$' + answer;
                 sent[2] := '';
                 sent[1] := 'You own this much Xanopieland money:';
                 sent[4] := '';
                 sent[5] := 'Press any key to continue...';
                 GetAnyKey(-1,-1);
              end;

              begin  {main}
                 centerjustify := true;
                 sent[1] := 'Universal Money Converter';
                 pop(25,2);
                 mc := 1;
                 repeat
                    sent[1] := 'Xanopieland';
                    sent[2] := 'Braze Island';
                    sent[3] := 'Nomania';
                    sent[4] := 'Grazille';
                    sent[5] := 'Exit to Dos';
                    doublemenu(-1,-1);
                    if (u = #13) then case mc of
                       1 : xano;
                    (* 2 : brace;
                       3 : nomania;
                       4 : grazille; *)
                    end
                    else
                    case upcase(u) of
                       'X' : xano;
                    (* 'B' : braze;
                       'N' : nomania;
                       'G' : grazille; *)
                       'E' : begin
                                mc := 5;
                                u := #13;
                              end;
                    end;
                 until (u = #13) and (mc = 5);
              end.

         There are opportunities for bugs here. You want to make  sure
         u = #13 (the [Enter] key) before allowing the first "case" to
         execute,  because  otherwise,  a procedure may run twice in a
         row if the user presses a character  key,  first  when  mc  =
         whatever,  then  then  when u = 'whatever'. Also make sure to
         put the second case characters in  single  quote  marks.  And
         last,  notice  the  "upcase(u)."  Without this the user would
         have to press the shift key to get the desired result. Upcase
         converts u into a capital letter.

         Prog20 is going to be a big, but very special program because
         it  will  be  something  you'll use everyday.  Run it and see
         what it does, then study the source code to understand it.

              program prog20;
              uses crt, magic;

              procedure extkey;               (* 1 *)
              var
                 tempstr : string[3];
                 ekey : boolean;
              begin
                 XClear;                         (* 8 *)
                 sent[1] := 'Press any key to see it''s extended code';
                 sent[2] := 'Press ''Q'' when done.';
                 pop(18,3);
                 sent[1] := ' ';    (* 9 *)
                 sent[2] := '';
                 repeat
                    ekey := false;
                    GetAnyKey(-1,-1);
                    if u = #0 then
                    begin
                       sent[1] := '#0 + ';
                       u := readkey;
                       ekey := true;
                    end;
                    case u of
                       #13 : answer := ' ';   (*  10  *)
                       #8  : answer := ' ';
                       #10 : answer := ' ';
                       #7  : answer := ' ';
                       else answer := u;
                    end; {case}
                    str(ord(u),tempstr);
                    sent[1] := sent[1] + answer + ' (#' + tempstr + ')';
                 until (upcase(u) = 'Q') and (ekey = false);
                 XClear;
              end;  {procedure ExtKey}

              procedure asciichart;
              var
                 x,y : byte;            (*  3  *)
                 temp : integer;
              begin
                 textcolor(white); textbackground(black);
                 x := 1;
                 y := 1;
                 clrscr;
                 for temp := 0 to 255 do
                 begin
                    u := chr(temp);   (* 4 *)
                    gotoxy(x,y);      (* 5 *)
                    write(' ');
                    if temp < 10 then write(' ');
                    if temp < 100 then write(' ');
                    if (temp <> 7) and (temp <> 8) and (temp <> 10)
                     and (temp <> 13) and (temp <> 27)   (* 11 *)
                     then write(temp,'=',u,' ')
                    else write(temp,'=');
                    inc(y);     (* 6 *)
                    if y > 25 then
                    begin
                       y := 1;
                       x := x + 7;
                    end;
                 end; {end of for 0 to 255 loop}
                 WaitForUser;
                 xclear;      (*  7  *)
              end; {procedure Asciichart}

              begin {main}
                 centerjustify := true;
                 mc := 1;
                 repeat
                    BoxBack := red;
                    sent[1] := 'Programmer''s Tools';
                    sent[2] := 'Copyright 1991, Freeware by Another Company';
                    pop(18,2);
                    BoxBack := green;
                    sent[1] := 'ASCII Chart';
                    sent[2] := 'Extended Keys';
                    sent[3] := 'Quit';
                    menu(-1,-1);
                    if u = #13 then
                    case mc of
                       1 : AsciiChart;            (* 2 *)
                       2 : ExtKey;
                    end;
                 until (u = #13) and (mc = 3);
                 CleanUp;
              end.

         I've tagged this file with note numbers surrounded by (*  and
         *).  Note 1) Don't look here to start reading a program, this
         is  merely  a  sub-routine.  Go  way down to the main program
         block, where it says "{main}" to get a feel for what's  going
         on.
             Looking at the overall program you'll see that  there  is
         the  main  program  block  and  two  procedures, which may be
         called from the case statement in the main block.

         Note 2) If the user  selects  the  first  menu  item,  "ASCII
         Chart"  then  MC will be 1, and the AsciiChart procedure will
         be called. Now let's go up and take a look at that procedure.

         Note 3) Here are some variables being  declared  within  this
         procedure.  They are not available to the main program. X and
         y  are bytes, they can hold a value of from 0 to 255. Temp is
         an integer, with a possible value of from  approx  -32000  to
         +32000. If you look down a few lines, you'll see that x and y
         are  specifically set to 1. In Pascal, as in most programming
         languages, the act of declaring a variable doesn't set it  to
         0  or  any other value. Unless specifically set to something,
         it's value will be random. In this procedure, the  values  of
         x and y need to start with 1.

         Note  4) We are in a "for" loop which as it is set up in this
         program will start with temp defined as 0  and  the  contents
         of  the  loop  (between the "begin" and "end" will repeat 255
         times, and each time, the value of temp will be increased  by
         1.
            The  first  thing  that  happens in this loop is that u, a
         global  char  variable,  is  set  to  the   ASCII   character
         represented  by  the value of temp. This is done by the Turbo
         Pascal function "chr."

         Note 5) The  next  thing  that  happens  in  this  loop  that
         repeats 255 times is "gotoxy." Gotoxy moves the cursor to the
         coordinates  in  the  parentheses.  Then,  with  close study,
         you'll figure out what  is  written  to  the  screen  by  the
         program in the several following lines of code.
            Following  this,  are  a  few  lines  to make columns on a
         single screen rather than simply scrolling  down  255  lines.
         I'll  let  you figure out how that's accomplished by studying
         the code.

         Note  6)  This  note  calls  your  attention  to  the   line,
         "inc(y)."  Inc adds 1 to an integer value. It is like saying,
         "y := y + 1. By doing this, when the next  iteration  of  the
         loop   occurs,  and  the  gotoxy  is  encountered,  the  next
         character will be written one line below  the  last,  because
         of y being one number higher.

         Note  7)  After  the  255  executions  of  the  for loop, the
         program calls the magic procedure  WaitForUser,  which  waits
         for  the  user  to  press  a key or click a mouse button. The
         next line is XClear, which clears the screen  in  preparation
         to return to the main program.

         Note  8)  is  way  up high in the code, in the top procedure.
         This procedure, ExtKey is the one which pops up the ASCII and
         Extended Key information in a little window for each key that
         is pressed. First thing this  procedure  does  is  clear  the
         screen  again.  Then  it makes a box with a couple of sent[]s
         explaining, "Press any key to see it''s extended  code,"  and
         "Press  ''Q''  when  done."  Look  at  all those single quote
         marks! There are two of them after in it''s, and  two  single
         quote marks in a row on either side of the ''Q''. No, they're
         not   typographical   errors.   This   is  how  Turbo  Pascal
         differentiates between the beginning and  end  of  a  literal
         string, and a string containing a ' in it. When there are two
         ''s, Pascal prints it on the screen as a single '. When there
         is just one ' in the source code, Turbo Pascal thinks you are
         trying to mark the beginning or end of a literal string.

         Note  9) The first time the ExtKey procedure runs, as you may
         recall, a little box containing nothing  appears,  until  you
         press  a  key to fill it. Sent[1] has to be something, or the
         program will think there are no sent[]s at all, so sent[1] is
         a one-character string containing a space.  sent[2]  must  be
         specifically   rewritten  as  a  string  containing  nothing,
         because the preceding pop had  used  two  sent[]s,  and  the
         information  in  sent[]s  is not cleared after a call to pop,
         as it would be in pop-up boxes that  automatically  disappear
         after they are done.

         Notes  10  and  11)  Some  characters,  when  written  to the
         "screen" do funny things.   #8  is  the  backspace  character
         which  will  actually  back up the cursor and cause something
         else to be overwritten.  #13 is a carriage return and #10  is
         a line feed, which would screw up a chart or anything you try
         to  display normally. #7 goes "beep!" So such characters must
         specifically eliminated if you try to  write  them  literally
         to the screen.

         This  is  an  excellent program to study in detail.  A really
         good way to understand it is to modify it.  Experiment.  Make
         changes,  and  see  if when you run the program, your changes
         act as you had expected. See  if  you  can  improve  on  this
         program  or  add  new  features. If you can understand all of
         this, you are well on your way to being a GOOD programmer.

         Prog21 is derived from  prog20.  It  is  a  demonstration  of
         writing  to a disk file. The object of this program is to put
         a column of ASCII equivalents in a text file, so you can  use
         it with your word processor, etc. Run prog21, then go look at
         the  file  called ASCII.TXT with the Turbo Pascal IDE or your
         favorite word processor.  Be  aware,  prog21  is  very  slow,
         requiring several seconds to run its course.

              program prog21;
              uses crt,magic;
              var
                temp : integer;
                tempstr : string;
              begin
                 NameOutFile('Ascii.txt');
                 for temp := 0 to 255 do
                 begin
                    str(temp,tempstr);
                    tempstr := tempstr + ' = ' + chr(temp);
                    FileWriteLn(tempstr);
                 end;
              end.

         There  are  two special items in the magic unit, "InFile" and
         "OutFile." InFile is used to get text in from  the  disk  and
         use   it   within  your  program.  OutFile  is  used  to  put
         information out to the disk. Essentially, these are  pathways
         to  disk files. You must give them names that will be used in
         the disk directory. As usual with  disk  files,  these  names
         must  be  DOS-legal,  with  up  to  8  characters, optionally
         followed by a period and up to a  three-character  extension.
         Drive  designator  and sub-directory designations can precede
         file names.

            So we would use OutFile to convey information to the disk.
         The first operation in prog21 is to associate a disk filename
         with outfile, using "NameOutFile."
            Then a for loop creates  a  string,  "tempstr"  containing
         each  ASCII  number  and  the  character  represented by that
         number. The line in  this  loop,  "FileWriteLn"  writes  this
         tempstr to the disk.
            There  is  another procedure called FileWrite which writes
         strings to disk, but does not put  each  one  on  a  separate
         line.  This  follows  the  convention of Turbo Pascal's Write
         and Writeln.
            If you have named a file that does not yet exist on  disk,
         it  will  be  created  automatically  with  the first call to
         FileWriteLn or FileWrite. If the  file  already  exists,  the
         string  passed with FileWriteLn or FileWrite will be appended
         to the end of the file.
            You'll  notice  two things about FileWriteLn, one iis that
         it  is  very  slow.   FileWriteLn   is   nice,   because   it
         automatically  does  several  things  that you would normally
         have to write separately into your program, but that's why it
         is slow.
            The  other  thing you'll see when you look at the finished
         file.  Some of the characters do funny things when written to
         a file, causing a sort of misalignment. These are things like
         line feed (#10) and Bell (#7), which beeps if read by the DOS
         type command.

         Prog22 is a variation of the previous  program  that  handles
         writing  to  file  more  manually, resulting in a much faster
         program, and eliminates the funny characters.

              program prog22;
              uses crt,magic;
              var
                 temp : integer;
                 tempstr : string;
                 outfile : text;
              begin
                 assign(outfile,'Ascii.txt');
                 rewrite(outfile);
                 for temp := 0 to 255 do
                 begin
                    str(temp,tempstr);
                    tempstr := tempstr + ' = ';
                    if (temp <> 7) and (temp <> 10) and (temp <> 13)
                    and (temp <> 26) then tempstr := tempstr + chr(temp);
                    writeln(outfile,tempstr);
                 end;
                 close(outfile);
              end.

         Cleaner and faster, eh?  I won't go  into  the  specifics  of
         file  handling  here, it is all well documented in your Turbo
         Pascal manuals. There are three types of files you  can  work
         with,  with  text  files  being  the  most  often used by new
         programmers, and there are many things you can do with  files
         besides  simple  reading  and  writing  of  strings. For that
         matter, there's a whole bunch  of  things  you  can  do  with
         strings, but all that is well beyond the scope of this humble
         tutorial.

         The  compliment of FileWriteLn is FileReadLn. Prog23 shows it
         in operation, using the previously created Ascii.txt.

              program prog23;
              uses crt,magic;
              var
                 tempstr : string;
              begin
                 clrscr;
                 NameInFile('Ascii.txt');
                 repeat
                    tempstr := FileReadLn;
                    writeln(tempstr);
                 until problem;
                 WaitForUser;
                 CleanUp;
              end.

         Not very elegant, since  the  stuff  scrolls  right  off  the
         screen,  but  you  get  the general idea. Notice the 4th line
         from the bottom: "until problem".  This introduces  something
         very  excellent  about  the magic unit. It is always watching
         for mistakes. If you ask most of the functions and procedures
         in the magic unit to do something that can't be done, they do
         not crash the program. Instead, they handle  the  problem  as
         gracefully  as  possible and set a global boolean variable to
         true. If there is no problem with your use of the function or
         routine problem is false.
            In this case, if you try to read beyond  the  end  of  the
         file,  FileReadLn  turns problem to true, and this particular
         program's repeat until loop falls through,  and  the  program
         ends.  If  you  forced the issue or wrote a program that does
         not regard "problem" then  any  subsequent  attempts  to  use
         FileReadLn would simply assign #0 to tempstr.
             In  Turbo  Pascal, files that are read from or written to
         must  first  be  opened,  the  operation(s)  performed,  then
         closed.   FileWrite   and   FileWriteLn   handle   all   this
         automatically, but FileRead and FileReadLn cannot, because if
         you were to make subsequent calls to these and they did  open
         and  close  the file each time, each time you read, you would
         always get the first line in the file, since opening a  file,
         resets it to the beginning.
             So from the first time you read the file with FileRead or
         FileReadLn,  InFile  remains open. It should be closed before
         the program ends, and the best way to do that is to call  the
         very  standard  procedure,  "CleanUp"  which  is specifically
         designed to be the last line in any program.  It  closes  all
         open  files,  resets  the  video  mode, clears the screen and
         frees up memory. It never hurts to have this line at the  end
         of any program, and it is essential at the end of some.
             If  you  have read several lines in infile, then you want
         to start over at the top, do this: "reset(infile)."

         Prog24 explores graphics a bit. Compile it, run it, study it.

              program prog24;
              uses crt, video, magic;
              begin
                 sent[1] := 'This is text mode';
                 GetAnyKey(-1,-1);
                 BestVideo;
                 sent[1] := 'This is a graphics mode';
                 GetAnyKey(-1,-1);
                 CleanUp;
              end.

         As you can see, it is quite simple.  There are only  two  new
         things  in this program.  Can you spot them? The first is the
         use of a new unit, "Video." The second is a procedure  called
         "BestVideo."  BestVideo  is a procedure that figures out what
         type of monitor you have, then sets up the program to run  on
         your graphics card.
            And there is a special surprise. Those  of  you  who  have
         done  some  graphics work in Turbo Pascal will recognize it's
         benefit right away. When you call BestVideo, it automatically
         incorporates the graphics drivers  into  your  compiled  .EXE
         file.  Usually,  the Borland Graphics Interface files (*.BGI)
         must be distributed on the disk along with your program.
            There are several video procedures within the magic  unit.
         They  are CGAVideo, HercVideo, EGAVideo, VGAVideo, BestVideo,
         and TextVideo. If you use HercVideo, in place  of  BestVideo,
         then  the  program  will  work  only on computers equipped to
         display Hercules Graphics, but the compiled program  will  be
         much smaller, and you can use absolute coordinates to display
         graphics.
            BestVideo  will  link  in  all  the  *.BGI  files and then
         automatically detect which graphics card is  present  in  any
         computer, and therefore will run on practically any IBM-clone
         that  has any graphics card. But BestVideo has to incorporate
         all the graphics drivers, and therefore the finished  product
         is  larger.  Furthermore,  when  using BestVideo, you have to
         account for different resolutions on different machines.   On
         a CGA machine, the coordinates 0,180 are near the bottom left
         edge  of  the  screen,  but  on VGA 0,180 is on the left, but
         nearer to the top of the screen. With BestVideo, you have  to
         make  calculations  based  on GetMaxX, and GetMaxY, (see your
         Borland books) or use centered pop-up boxes.
             TextVideo is the way out of graphics.  For  instance,  if
         you write a program that starts in graphics mode to display a
         drawing,  then  you  want  to  switch back to text for faster
         handling of strings, you simply call the TextVideo procedure.
             Pop, GetYN, GetAnyKey, Dialog, Menu  and  DoubleMenu  all
         work almost the same in any graphics mode as in text mode.

              program prog25;
              uses crt, video, magic;
              begin
                 sent[1] := 'This is text mode';
                 GetAnyKey(-1,-1);
                 CGAVideo;
                 sent[1] := 'This is a graphics mode';
                 GetAnyKey(-1,-1);
                 TextVideo;
                 sent[1] := 'This is text again';
                 GetAnyKey(-1,-1);
                 CleanUp;
              end.

         Prog25 switches to CGA graphics mode, then back to text mode.

         Prog26 shows some of the complexity in using BestVideo.

              program prog26;
              uses crt, video, graph, magic;
              begin
                 sent[1] := 'This is text mode';
                 GetAnyKey(-1,-1);
                 BestVideo;
                 setcolor(yellow);
                 circle(getmaxx div 2,GetMaxY div 2, GetMaxY div 4);
                 sent[1] := 'This is a graphics mode';
                 GetAnyKey(-1,-1);
                 TextVideo;
                 CleanUp;
              end.

         Notice the new unit.  We are now using a unit that comes with
         Turbo Pascal called Graph.tpu.  It allows us to make circles,
         rectangles, lines, change colors, and many other things.  You
         should  use Graph in all your graphics programs because those
         which don't make use of it will not be much larger than those
         that do. Borland's compiler is smart and strips  unused  code
         out of units as the program is compiled.
            This one switches to a graphics when a key is pressed.  If
         you have a VGA system, then you'll see a yellow circle around
         a  pop-up  box.  But,  then  change  the  "BestVideo" line to
         "CGAVideo" and you'll  see  that  the  pop-up  box  partially
         covers  the  circle, even though the circle is supposedly the
         same size. It's the pop-up that changed.
            Notice that you can  change  color  by  simply  passing  a
         color to SetColor.

         Prog27  shows  a few of the many other things you can do with
         the Turbo Pascal Graph unit.

              program prog27;
              uses crt, video, graph, magic;
              begin
                 BestVideo;
                 SetColor(white);
                 circle(100,100,50);
                 circle(100,100,40);
                 SetFillStyle(solidfill,white);
                 FloodFill(51,100,white);
                 SetColor(lightgreen);
                 SetLineStyle(0,0,3);
                 rectangle(70,70,130,130);
                 SetFillStyle(solidfill,lightmagenta);
                 bar(90,90,110,110);
                 WaitForUser;
                 CleanUp;
              end.

         Prog28 shows how to work with text in a graphics mode.  Turbo
         Pascal  supplies  a  default  font,  which  is an 8 x 8 pixel
         bitmapped font. It is called DefaultFont.

              program prog28;
              uses crt, video, graph, magic;
              begin
                 BestVideo;
                 OutTextXY(10,100,'This is the Default font');
                 WaitForUser;
                 CleanUp;
              end.

         In Prog28 we see that the way to display a string is  through
         OutTextXY,  which is similar to GoToXY combined with Write in
         text mode. OutTextXY  requires  screen  coordinates,  then  a
         string.   Unlike  write  and  writeln,  you  must pass only a
         string and only one string at a time. You must "str"  numbers
         before using OutTextXY.

         Prog29 shows how to work with different fonts.

              program prog29;
              uses crt, video, graph, magic;
              begin
                 BestVideo;
                 Triplex;
                 SetTextStyle(TriplexFont,HorizDir,4);
                 OutTextXY(0,0,'This is the Triplex font');
                 WaitForUser;
                 CleanUp;
              end.

         First,  you'll  see  a call to "Triplex." This will cause the
         external Triplex.Chr file to be compiled  directly  into  the
         .EXE  file.  You  do not have to distribute finished programs
         with external *.chr files! But  by  itself,  Triplex  has  no
         other effect on the program.  If you want to actually use the
         Triplex  font,  you  have to use "SetTextStyle". SetTextStyle
         takes three parameters. First is an integer for the  font  to
         use,  and  these integers also have pre-declared constants in
         the graph  unit.  Triplex  can  be  referred  to  as  "1"  or
         TriplexFont.   The   second   number   or   constant  is  the
         orientation of the text. HorizDir  is  the  most  common,  of
         course.  It can also be represented with a 0. And finally the
         size of the font can be controlled with another integer value
         from 1 to 10.
            As tempting as it may seem, there are two reasons  not  to
         use  any fonts except DefaultFont with Pop, GetYN, GetAnyKey,
         Dialog,  Menu  or Doublemenu.  Gothic, Triplex, SansSerif and
         Small fonts are drawn rather  than  bitmapped  and  therefore
         take  longer  to  generate on the screen, slowing the program
         perceptably.  Furthermore,  because  of  the  way  they   are
         generated, they don't line up right relative to the general x
         and y coordinates used by these procedures.

         If you run prog29 in CGA mode (you can  change  BestVideo  to
         CGAVideo  to  see)  you'll  notice  that  the  line, "This is
         Triplex font." is too long to  fit  on  the  screen.  So,  in
         prog30, lets switch to a different CGA graphics mode.

              program prog30;
              uses crt, video, graph, magic;
              begin
                 CGAVideo;
                 SetGraphMode(4);
                 Triplex;
                 SettextStyle(TriplexFont,HorizDir,4);
                 outtextxy(0,0,'This is the Triplex font');
                 WaitForUser;
                 CleanUp;
              end.

         The line, "SetGraphMode(4)" changes to the higher resolution,
         2 color, 640 x 200 CGA mode.

         Prog31  shows  off  some  basic  mouse  work,  and  the  main
         principal of drawing to the screen.

              program prog31;
              uses crt, video, graph, magic;
              var
                 x,y : word; {"word" is a positive integer value}
              begin
                 BestVideo;
                 WasteMouse;
                 repeat
                    poll(x,y,left,right);
                    LineTo(x,y);
                 until left;
                 CleanUp;
              end.

         In prog31 a loop repeats until left becomes true. Left  is  a
         global  boolean  variable  that  is set to true when the user
         clicks the left mouse button. Poll is a  function  that  asks
         the mouse to report it's current status. It tells you through
         poll, the current screen position, in this case using x and y
         as word type variables for coordinates, and the status of the
         left and right mouse buttons. Every time the mouse is polled,
         a  line is drawn from where the last line ended, to where the
         mouse is currently.
             Notice the line, "WasteMouse." This is a procedure  which
         stalls  the  program until both "left" and "right" are false.
         (no mouse buttons pressed). Without "WasteMouse" the  program
         might end immediately.

         Prog32  shows  you  one  way to move a rectangle around. This
         program will display the mouse pointer until the  left  mouse
         button  is  clicked,  then  it  will  turn  it off and show a
         movable rectangle until the right mouse button is clicked.

              program prog32;
              uses crt, video, graph, magic;
              var
                 x,y : word;
              begin
                 BestVideo;
                 WasteMouse;
                 PointerToXY(GetMaxX div 2,GetMaxY div 2);
                 PointerOn;
                 repeat Poll(x,y,left,right) until left;
                 PointerOff;
                 SetWriteMode(XOrPut);
                 rectangle(x,y, x + 40, y + 20);
                 repeat
                    rectangle(x,y, x + 40, y + 20);
                    Poll(x,y,left,right);
                    rectangle(x,y, x + 40, y + 20);
                 until right;
                 CleanUp;
              end.

         Prog32 shows you how to turn the mouse pointer  on  and  off,
         and  shows  "SetWriteMode"  so  that you can eliminate images
         which  have  been  created,  by  merely  writing  them   over
         themselves.

         Prog33 shows a couple of small improvements:

              program prog33;
              uses crt, video, graph, magic;
              var
                 x,y,oldx,oldy : word;
              begin
                 BestVideo;
                 WasteMouse;
                 SetTextJustify(CenterText,BottomText);
                 OutTextXY(GetMaxX div 2,GetMaxY - 4,
                   'Click right mouse button to end program');
                 SetWriteMode(XOrPut);
                 rectangle(x,y, x + 40, y + 20);
                 repeat
                    repeat
                       Poll(x,y,left,right);
                    until (x <> oldx) or (y <> oldy) or right;
                    rectangle(oldx,oldy, oldx + 40, oldy + 20);
                    oldx := x;
                    oldy := y;
                    rectangle(x,y, x + 40, y + 20);
                 until right;
                 CleanUp;
              end.

         First,  we  took  off the mouse pointer stuff to simplify the
         program.  Then we use one of the fancy features of the  Turbo
         Pascal  Graph  unit to cause text to be centered from left to
         right around the x coordinate and the bottom  of  the  string
         will  be  on the y coordinate. And a notice is posted for the
         user.
            Then using the new variables, "oldx" and "oldy" within the
         repeat loop, we check to see if there have been  any  changes
         in  position  before  moving  the  rectangle. This eliminates
         annoying flashing.

         In our last program I'll  show  you  how  to  use  the  sound
         effects in the magic unit, and we'll fool around with text in
         graphics modes a bit more.

              program prog34;
              uses crt, video, graph, magic;
              var
                 x,y,oldx,oldy : word;
              begin
                 SoundUp;   (* 1 *)
                 MainBack := black;    (* 2 *)
                 BestVideo;
                 Gothic;     (* 3 *)
                 Triplex;
                 SetColor(LightMagenta);
                 SetTextJustify(CenterText,TopText);   (* 4 *)
                 SetTextStyle(GothicFont,HorizDir,6);
                 OutTextXy(GetMaxX div 2,0,'Type Anything');
                 SetTextStyle(TriplexFont,VertDir,1);
                 SetTextJustify(LeftText,CenterText);
                 OutTextXY(20,(GetMaxY div 2) + 30,'Press [Enter]');
                 OutTextXY(40,(GetMaxY div 2) + 30,'when done.');
                 SetTextStyle(DefaultFont,HorizDir,2);
                 SetTextJustify(LeftText,TopText);
                 SetFillStyle(SolidFill,black);   (* 5 *)
                 SetColor(LightCyan);
                 Waste;              (* 6 *)
                 answer := '';
                 repeat
                    u := ReadKey;
                    pink;    (* 7 *)
                    if ord(u) > 31 then answer := answer + u;  (* 8 *)
                    if u = #8 then   (* 9 *)
                    begin
                       bar(70,100,70 + TextWidth(answer), (* 10 *)
                         100 + TextHeight(answer));
                       delete(answer,length(answer),1);  (* 11 *)
                    end;
                    OutTextXY(70,100,answer);
                 until u = #13;
                 SoundDown;
                 delay(500);  (* 12 *)
                 Twinkle;
                 CleanUp;
              end.

         Prog34 has notes within (* and *):

         Note  1)  One  of the four sound effects built into the magic
         unit. To use one of the effects, simply call it's  procedure.
         Sometimes  sounds  don't  behave  as  expected  with machines
         faster  than  33mhz  or  when  heavily  multitasked  (running
         concurrently   with   other  programs)  under  MS-Windows  or
         Deskview.

         Note 2) By setting the main background color to black  before
         a call to BestVideo, the video mode will start and run with a
         black background.

         Note  3) These procedures, Gothic and Triplex hook in the two
         fonts besides the default font that this program is going  to
         use. There will be no need for *.chr files on the disk with a
         compiled program.

         Note 4) SetTextJustify will center a title on the screen when
         set this way.

         Note  5)  SetFillStyle  is  used  to establish parameters for
         "bar," used a few lines down in this program.  Bar will  make
         a solid rectangle in the color specified (black in this case)
         This is a good way to erase text in graphics modes.

         Note  6)  Waste stalls the program until no mouse buttons are
         pressed  and  no  characters  have  been  entered  from   the
         keyboard.   If  a  key  had  been pressed as this program was
         starting, it would be reflected as the first character  in  a
         string the user is going to type.

         Note  7) "Pink" is a sound effect, typically used to indicate
         a small action has occurred, such as a key has been pressed.

         Note 8) "Ord" returns the ordinal position in a  set  of  the
         variable  specified  in  parentheses.   When  used with ASCII
         characters, Ord returns their ASCII number.  What  this  line
         does  is  eliminates  adding  characters to the string called
         "answer" if they might be unprintable characters.

         Note 9) u is  ASCII  #8  when  the  backspace  key  has  been
         pressed.

         Note  10)  "Bar"  is  being  used  to erase "answer" from the
         screen  because  the  backspace  key  has  been  pressed  and
         therefore  the  user wants to eliminate the last character in
         answer.  The Bar will  erase  it,  and  a  newer  version  of
         answer,  one  which  will  be  one  character shorter will be
         written in its place. TextWidth and TextHeight are  excellent
         functions  provided  by  Turbo  Pascal  to determine how many
         pixels wide and how many pixels high a string are, no  matter
         what font and size are selected.

         Note 11) "Delete" is a  way  to  shorten  a  string.   Delete
         requires  three  parameters,  the string on which to operate,
         the character position in the string at which to delete,  and
         the number of characters to take out. There are several other
         string  procedures  available from Turbo Pascal including Pos
         (find the position of a matching sub-string within a string),
         Copy (make a sub-string from a string), and ConCat  (add  two
         strings  together). See your Borland Turbo Pascal manuals for
         more information about string handling.

         Note  12)  Delay  is  called between two sound effects to put
         some time between them. Delay requires one number, an integer
         representing the number of milliseconds to delay.  There  are
         1000 milliseconds in one second, so this delay is 1/2 second.
         While Delay is running, no other actions can take place.

                                     - - -

            And  that almost wraps up this tutorial! Hope you have had
         as much fun reading and experimenting as I did writing it.
            There  is  far  more  available  in Turbo Pascal than this
         short tutorial can tell you about.  To learn as much  as  you
         can,  in  a  reasonable  amount  of time, I recommend getting
         several books on Turbo Pascal, and experimenting  with  every
         idea that crosses your mind.
            In  fact,  there's  quite  a  bit  more  to the Magic unit
         itself.   You  can  read   Magic.Doc   to  learn  more of its
         included procedures and functions,  and  get  more  technical
         information on the ones you already know.
            This is shareware. Feel free to copy and distribute Pascal
         Magic as long as all files remain intact and unchanged.
            If  you  have  paid a professional shareware distributor a
         few dollars for this disk, you have paid for the  service  of
         providing a copy.
            If  you  use  MAGIC.TPU  in  your programs, or if you have
         found this tutorial helpful, you must pay for the creation of
         the product. Send $29.95 to:

                                Another Company
                                 P.O. Box 298
                              Applegate, OR 97530

            Complete source code is available for the MAGIC.TPU.  This
         is good for using as a framework for your own very customized
         applications,   for   learning   more   about   Turbo  Pascal
         Programming, for  stripping  down  top  efficiency,  and  for
         improving,  since  you  will  probably  soon become (or might
         already be) a better programmer than I am.  For  registration
         AND source code, send $59.90 and please specify disk size.

         This is version 1.0 and you may find a bug or two.  I make no
         guarantees about it's suitability to your programming needs.

         If  we  find  any major bugs, they will probably be corrected
         by the time you get your registered version!

         If  you require technical assistance, you can try to phone me
         at 503-846-7884. Best bet is 9-5 weekdays, but I'm not always
         available.

         Since you are going to write  some  wonderful  programs,  you
         might as well start making money with them! You won't have to
         work  in  an  office doing programming for someone else.  You
         can write exactly the kind of programs you want to write, and
         make money at home!
             The  'secret'  is shareware.  Does it work?  You bet! You
         can easily have a small success, making some  extra  spending
         money  each month, or with some practice, you can have a wild
         success, and make a fine living! There are some  millionaires
         who   make   their   ever-growing  fortune  entirely  through
         shareware.
             ANOTHER  COMPANY  shows  you everything.  Besides our own
         shareware  successes,  including  WRITER'S   DREAM,   BICYCLE
         TUNE-UP  AND  REPAIR,  MONEY,  BLACKBOARD,  BETTER  EYESIGHT,
         WHAT'S  IN  THAT  BOX?  and  THE UNIVERSAL CONVERTER, we have
         researched the shareware market, we  have  interviewed  other
         shareware  authors  and  have  learned about all sides of the
         rapidly expanding shareware business.
              We show you how  to  write  programs  that  capture  the
         public's   interest,   how   to   make  sure  your  customers
         'register', and how to get money by other means through  your
         shareware.  We  show  you  more. We show you frequency charts
         indicating which  types  of  programs  sell  best,  we  offer
         suggestions  for  programs as yet unwritten,  we  talk  about
         your  on-disk  instruction  manuals,  we even show you how to
         write user-friendliness into your programs.
              Can  you  succeed without  SUCCESS WITH SHAREWARE?  Yes!
         But  why do  it  the  hard  way?  We  have  learned  all  the
         super-professional   approaches,   the   pitfalls   and   the
         shortcuts. We'll tell you all about it, and then  instead  of
         stumbling  around  for  the  first couple of years, you'll be
         a professional from the start!
             To get your copy of SUCCESS WITH SHAREWARE! (which is not
         shareware, itself - only  available  from  Another  Company),
         send $19.95. Please specify if you need 3.5" disk size.

                                                         Thanks,
                                                     - Jeff Napier -
                                                     January 9, 1992

         You can order products by writing your order on plain  paper,
         or  by  printing the included ASCII file called Order.frm, or
         by phoning 1-503-846-7884, generally weekdays between  9  and
         5, west coast time.
