home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / pascal / tpmagic.zip / TUTORIAL.TXT < prev    next >
Text File  |  1992-01-18  |  88KB  |  1,802 lines

  1.  
  2.                                  PASCAL MAGIC
  3.  
  4.                (c) Copyright 1992, Jeff Napier & Another Company
  5.  
  6.  
  7.                                  Tutorial File
  8.  
  9.  
  10.          What Pascal Magic can do for you:
  11.  
  12.             This  disk  consists  of three parts, Magic.Tpu, Magic.Doc
  13.          and  Tutorial.Txt. Magic.Tpu is an add-in for Borland's Turbo
  14.          Pascal version 6.0 which will make your job as  a  programmer
  15.          much easier and your results much more polished. Magic.Doc is
  16.          a  text  file  which  explains how to use all the features of
  17.          Magic.Tpu, and Magic.Tut, the file you are now reading, is  a
  18.          tutorial  which starts at a very beginning level and quickly,
  19.          but effortlessly moves into advanced programming techniques.
  20.  
  21.          Specifically, Magic.Tpu offers the following:
  22.  
  23.          *  Automatic  pop-up  text  boxes, dialog boxes and light-bar
  24.          menus.
  25.  
  26.          * Automatic handling of text files.
  27.  
  28.          * Built-in mouse support for the programs you create.
  29.  
  30.          * Support for graphics programs to make them as easy to write
  31.          as text-based programs.
  32.  
  33.          * Incorporation of .BGI and .CHR files directly into finished
  34.          .EXE files.
  35.  
  36.          * Sound effects for your programs.
  37.  
  38.          * Simplification of many Turbo Pascal operations.
  39.  
  40.          * Complete color control in text and graphics modes.
  41.  
  42.          * Build cursor control into  your  programs  for  laptop  LCD
  43.          screens.
  44.  
  45.          *   Full,   documented,  easy-to-understand  source  code  is
  46.          available  so  you  can  learn  from  and customize the Magic
  47.          framework to your own applications.
  48.  
  49.                                      NOTE:
  50.  
  51.             This  is  a  shareware  product.   You  have  our specific
  52.          permission to copy and distribute this package as long as all
  53.          files remain intact and unchanged.
  54.             If  you  benefit  from  this  tutorial,  or if you use the
  55.          Magic.Tpu unit in your programs you are expected to register.
  56.          To register, send $29.95 to:
  57.  
  58.                                 Another Company
  59.                                  P.O. Box 298
  60.                               Applegate, OR 97530
  61.                                       USA
  62.  
  63.          If  you  would  like  the  full   source   code   with   your
  64.          registration, send $59.90. Please specify disk size.
  65.  
  66.                                   QUESTIONS:
  67.  
  68.          If you have questions: 503-846-7884, 9-5 Weekdays, West Coast
  69.          time. (We are not always available during those hours.)
  70.  
  71.                       THE BEST WAY TO USE THIS TUTORIAL:
  72.  
  73.          Copy  Magic.Tpu  to  the directory where you keep your Pascal
  74.          *.tpu files, and copy Tutorial.txt  to  the  directory  which
  75.          contains  your  *.pas files. Start your Turbo.Exe and load in
  76.          this file, (type: TURBO TUTORIAL.TXT). Since the Turbo Pascal
  77.          IDE  (Integrated  Development Environment) allows you to work
  78.          on several files at once, you can read this tutorial  in  one
  79.          window  and  work on practice programs in another window.  If
  80.          you don't know how  yet,  I'll  show  you.   If  you  are  an
  81.          experienced  programmer,  you might want to skip through this
  82.          tutorial and concentrate only on the areas that  are  new  to
  83.          you.
  84.  
  85.                            A COUPLE OF OTHER NOTES:
  86.  
  87.          1. It is assumed that you have legally purchased Turbo Pascal
  88.          version  6.0  and  therefore  have  the four valuable printed
  89.          manuals that come with the program. If not, you  are  advised
  90.          to  go  spend  a  little money and get what you need, because
  91.          there are places within this tutorial which will refer you to
  92.          those books to complete your knowledge.
  93.  
  94.          2. This is not the last word  on  Turbo  Pascal.  It  doesn't
  95.          teach  everything  about  programming  - probably not even 10
  96.          percent of what you will eventually learn, but  between  this
  97.          tutorial  and  the Borland manuals, you'll get pretty good at
  98.          programming, and fairly quickly. One  of  the  best  ways  to
  99.          learn  this  is  to  experiment  frequently. Tear the example
  100.          programs apart and try to interject your own ideas into them.
  101.          See what you can change or improve, then run the programs you
  102.          have modified and see what happens. As  you  well  know,  you
  103.          can't hurt your computer by typing an incorrect line of code.
  104.  
  105.          3.  Turbo  Pascal is not sensitive to capitalization or white
  106.          space. The exact placement of indentations is  not  important
  107.          and  every programmer develops a slightly different style. In
  108.          this tutorial, I have  tried  to  capitalize  letters  within
  109.          procedure  and  function  names where such capitalization may
  110.          make the source code easier to read. This 'convention' occurs
  111.          irregularly throughout this tutorial.
  112.  
  113.          4. This is version 1.0 of  what  I  believe  is  a  wonderful
  114.          product,  but  then, I wrote it.  Let me know what you think.
  115.          I'm pretty sure I caught all the major bugs, but there may be
  116.          some minor ones. Most likely the registered and/or subsequent
  117.          shareware versions will be even better!
  118.  
  119.          5.  To use Magic.tpu, Video.tpu and Fonts.tpu will also  need
  120.          to  be  available in the same sub-directory. Also, Graph.tpu,
  121.          furnished with Turbo Pascal must be in the sub-directory.
  122.  
  123.  
  124.                                   HERE WE GO:
  125.  
  126.          Here is the simplest program you can write:
  127.  
  128.               begin
  129.               end.
  130.  
  131.          Let's try it out. Press  [F3].  (First  finish  reading  this
  132.          paragraph  so  you  know  how  to get back.) A window pops up
  133.          asking for a file name.  Call  it  Prog1  (or  any  name  you
  134.          choose)  and  type  the  preceding  two-line  program.  Don't
  135.          forget the period after end. In Pascal, there is no  need  to
  136.          care about capitalization, Capitals, small case or mixed-case
  137.          makes  no  difference.  Press [F2] to save your valuable work
  138.          against power failure, etc. While  holding  the  [Ctrl]  key,
  139.          press  [F9]  and  the program will run. Did you blink? Since,
  140.          the program  doesn't  actually  do  anything,  it  runs  very
  141.          quickly,  then returns to Turbo Pascal. To switch back to the
  142.          first window, press [Alt] and [1].
  143.  
  144.          This next program is just  like  the  first,  it  doesn't  do
  145.          anything,  but  it is also a legal program. There is one more
  146.          line starting with the word Program. Some versions of  Pascal
  147.          require this line, but with Turbo Pascal, it is optional.
  148.  
  149.               program prog2;
  150.               begin
  151.               end.
  152.  
  153.          Next,  we'll add something to the program so it will actually
  154.          have a purpose:
  155.  
  156.               program prog3;
  157.               begin
  158.                  write('Hello, World!');
  159.               end.
  160.  
  161.          This program only  does  one  thing,  it  "write"s  the  text
  162.          between  the  single quote marks to the screen. Turbo Pascal,
  163.          like all computer applications is sensitive to exact spelling
  164.          and punctuation. Make sure you have a colon at the end of the
  165.          write('Hello, World!'); line, and that all the  other  pieces
  166.          are in their proper places.
  167.              Go  ahead  and  run  this program. Press [Alt] and [2] to
  168.          get back to the other window you opened, and add the lines to
  169.          make the first program into this one. Or, if  you  wish,  you
  170.          can  make  a block around this prog3, using the mouse or with
  171.          ^KB the arrow keys ^KK, (actually there are several  ways  to
  172.          mark  a block). Then press [Alt] and [E], then [C]. This puts
  173.          a copy of the marked block in  the  Turbo  Pascal  clipboard.
  174.          Switch  to  the  other  window (use [Alt]-[2], or [Alt]- [W],
  175.          [L]). Then press [Alt]-[E], then [P] to paste the block  into
  176.          the  second  window. Erase the previous program, then compile
  177.          and run the new prog3.
  178.              It happened very quickly, didn't it? Lets slow it down in
  179.          prog4:
  180.  
  181.               program prog4;
  182.               begin
  183.                  write('Hello, World!');
  184.                  readln;
  185.               end.
  186.  
  187.          In prog4, the line readln causes the computer to wait for the
  188.          user to press the [Enter] key.  Now  you  can  take  time  to
  189.          contemplate your "Hello, World!" line.
  190.              You  may  notice  that the screen wasn't cleared of other
  191.          junk when prog4 ran. In prog5, let's clear the screen, giving
  192.          the  "Hello,  World!"  line  more  clarity.  We'll  use   the
  193.          procedure  clrscr,  which  Turbo Pascal provides to clear the
  194.          screen.
  195.  
  196.               program prog5;
  197.               begin
  198.                  clrscr;
  199.                  write('Hello, World!');
  200.                  readln;
  201.               end.
  202.  
  203.          What happened? If you tried to run this program, you'll  have
  204.          noticed  that it didn't work. Turbo Pascal does not recognize
  205.          "clrscr." Did I misspell it?  No.  I  didn't  tell  you  that
  206.          clrscr is not part of Turbo Pascal itself. It is in a library
  207.          of operations for screen handling called Crt.
  208.             Turbo  Pascal  provides  5  special libraries of routines,
  209.          called units. They are Crt,  System,  Printer,  Printer,  and
  210.          Dos.  You  can  also  create  your  own  custom units, or buy
  211.          special units from programmers.
  212.             These 5 are special because they are grouped together in a
  213.          special file called Turbo.Tpl, but usually units are separate
  214.          files  with the extension of .Tpu. The corrected prog5a shows
  215.          how to use a unit:
  216.  
  217.               program prog5a;
  218.               uses crt;
  219.               begin
  220.                  clrscr;
  221.                  write('Hello, World!');
  222.                  readln;
  223.               end.
  224.  
  225.          As the proper prog5 indicates,  to  use  something  within  a
  226.          unit,  simply  declare  the  unit's  name in the "uses" line,
  227.          which you must type just below the "program" line, or as  the
  228.          first  line  in  the program.
  229.  
  230.          Let's get a bit fancier, take a look at prog6.
  231.  
  232.               program prog6;
  233.               uses crt,magic;
  234.               begin
  235.                 sent[1] := 'Hello, World!';
  236.                 GetAnyKey(5,11);
  237.               end.
  238.  
  239.          Prog6 uses the Magic.Tpu unit. Give this program a try.  Kind
  240.          of  prettier,  isn't  it?  Let's  talk about prog6 in detail.
  241.          You'll  notice  that  instead  of  writing  "Hello,   World!"
  242.          directly  to  the  screen,  we  have  assigned that string of
  243.          characters to a variable called "sent[1]." In the magic unit,
  244.          "sent" is an array of sentences called strings. An array is a
  245.          group of something, all of which are the same type and  size.
  246.          The  "sent" array is 46 strings, each of which can contain up
  247.          to 76 characters. In prog6, we have used only  one  of  them,
  248.          the first one, number [1]. When you want to specify a certain
  249.          item  from  an  array  of items, you put its number in square
  250.          brackets. Until sent[1] was told to equal with  ":="  (called
  251.          "assignment  equals")  "Hello, World!," it was nothing. Until
  252.          prog6 assigned "Hello, World!" to it, sent[1]  was  equal  to
  253.          nothing,  like  this:  sent[1]  := ''. In fact, all the other
  254.          sent[]s in prog6 are still nothing. The magic unit  will  use
  255.          only the sent[]s which contain data.
  256.             The  next  line,  "GetAnyKey(5,11)" calls a procedure that
  257.          displays the  sent[]s  which  contain  data  in  a  bordered,
  258.          shadowed  box,  and  waits  for  the user to press any key or
  259.          click a mouse button. The two numbers following GetAnyKey are
  260.          coordinates. These refer to the position on the screen  where
  261.          the  box is to pop up. Specifically, they mark the upper left
  262.          corner of the pop-up box.
  263.             The first number is the horizontal position on the screen.
  264.          If  it  were  1,  then the box would be jammed up against the
  265.          left  hand edge of the screen. 80 is the right-hand edge of a
  266.          standard text screen since it is 80 characters wide, but  you
  267.          can't  put  the  left edge of a text box there if you want to
  268.          see it.
  269.             The  second number is, of course, the vertical coordinate,
  270.          with 1 being the top of the screen and 25 being the bottom.
  271.             You'll notice, that clrscr is missing. It  is  not  needed
  272.          with  the magic unit, since the unit automatically clears the
  273.          screen when the program starts. But, I left "Crt" in the uses
  274.          statement. This is easy programming practice, because if  you
  275.          don't  use  anything from the Crt unit, Turbo Pascal does not
  276.          increase the size of the compiled program. Yet, if  you  need
  277.          something  from  the unit, it is at your disposal. You'll see
  278.          that many of my programs "use" the Crt unit, even though they
  279.          don't end up using anything in the Crt unit.
  280.  
  281.          Prog7 illustrates a close relative to GetAnyKey, GetYN. While
  282.          GetAnyKey waits for the user to press almost anything,  GetYN
  283.          stalls  the  program  until  the  user presses [Y] or [N], or
  284.          clicks the left or right mouse button. Also, you'll note that
  285.          one  of  the  coordinates  is  a  negative  number.  In   the
  286.          preceding  paragraphs,  you'll notice  I didn't allow for the
  287.          possibility of a negative screen coordinate, and  technically
  288.          there is no such thing.  When the magic unit comes  across  a
  289.          negative  coordinate, it ignores the number and automatically
  290.          figures out where the center of the screen is and pops up its
  291.          box there!  In other words, if you pass a negative number for
  292.          the vertical location, the box will be between  the  top  and
  293.          bottom  of  the  screen. If you use a negative number for the
  294.          horzontal location, the box will be centered right to left on
  295.          the screen.
  296.  
  297.               program prog7;
  298.               uses crt, magic;
  299.               begin
  300.                 sent[1] := 'Do you want to quit? (Y/N)';
  301.                 sent[2] := '';
  302.                 sent[3] := 'This is just a test, actually, the program';
  303.                 sent[4] := 'is gonna quit whether you answer Y or N';
  304.                 GetYN(-5,3);
  305.               end.
  306.  
  307.          Let's make a slight improvement in the  next  program.  Prog8
  308.          changes  a  boolean variable, declared from the magic unit. A
  309.          boolean is a variable which can have only two values, true or
  310.          false. This particular variable is  CenterJustify.  Normally,
  311.          it is false (the "default" condition) but if changed to true,
  312.          then  the  strings  in the sent array will be centered within
  313.          any pop-up box. Run prog8 and you'll see what I mean.
  314.  
  315.               program prog8;
  316.               uses crt, magic;
  317.               begin
  318.                 sent[1] := 'Do you want to quit? (Y/N)';
  319.                 sent[2] := '';
  320.                 sent[3] := 'This is just a test, actually, the program';
  321.                 sent[4] := 'is gonna quit whether you answer Y or N';
  322.                 CenterJustify := true;
  323.                 GetYN(-5,3);
  324.               end.
  325.  
  326.          Prog8 is a little prettier, n'est ce pas? Prog9 will walk its
  327.          talk, it won't end until the user says "yes" by pressing [Y].
  328.          It uses  a  repeat  loop,  which  simply  repeats  everything
  329.          between  the  words  "repeat" and "until" until the condition
  330.          listed after "until" is true. GetAnyKey and  GetYN  wait  for
  331.          the  user  to  press  a  key. The difference is that GetYN is
  332.          specific, it waits for the key pressed  to  be  'Y'  or  'N'.
  333.          Both  of  these  procedures  assign  the character of the key
  334.          pressed to a global character variable  called  U.  So,  when
  335.          GetAnyKey or GetYN are done, u becomes what the user pressed.
  336.          In  the  special  case  of GetYN, if the user pressed a small
  337.          case 'y' or 'n', it is automatically converted into a capital
  338.          letter. Furthermore, GetYN makes u := 'Y' if the  left  mouse
  339.          button  was  clicked,  and u := 'N' if the right mouse button
  340.          was clicked.
  341.  
  342.               program prog9;
  343.               uses crt, magic;
  344.               begin
  345.                 repeat
  346.                    sent[1] := 'Do you want to quit? (Y/N)';
  347.                    GetYN(-5,3);
  348.                 until u = 'Y';
  349.               end.
  350.  
  351.          Prog10 introduces a new magic procedure called  Dialog.  With
  352.          this,  you  can  pose  a  question, and have the user type an
  353.          answer. Try it.
  354.  
  355.               program prog10;
  356.               uses crt, magic;
  357.               begin
  358.                  sent[1] := 'How would you answer this question?';
  359.                  Dialog(-1,-1);
  360.                  sent[1] := 'User typed:';
  361.                  sent[2] := Answer;
  362.                  GetAnyKey(-1,-1);
  363.               end.
  364.  
  365.          Prog10 allows the user to  type  the  answer,  then  if  your
  366.          program  were  more  sophisticated  that  prog10,  you  could
  367.          process that answer.  The answer is contained in  the  global
  368.          string  variable  Answer  which GetAnyKey uses to display the
  369.          result. Notice  that  "User  typed:"  is  in  single  quotes,
  370.          telling  GetAnyKey  to type literally that, but Answer is not
  371.          in quotes, telling it to print the string represented by  the
  372.          variable answer, and not type "Answer".
  373.  
  374.              In  prog10,  you  could  make  the  whole  operation more
  375.          evident if you used some color control. Try prog11.
  376.  
  377.               program prog11;
  378.               uses crt, magic;
  379.               begin
  380.                  sent[1] := 'How would you answer this question?';
  381.                  Dialog(-1,-1);
  382.                  BoxBack := White;
  383.                  Border := LightBlue;
  384.                  BoxText := Green;
  385.                  Shadow := Magenta;
  386.                  sent[1] := 'User typed:';
  387.                  sent[2] := Answer;
  388.                  GetAnyKey(-1,-1);
  389.               end.
  390.  
  391.          Prog11 is ugly, but you can see  how  to  change  the  colors
  392.          within  the text box. The colors seem to be used here as some
  393.          sort  of  variables  and  they  are.  They  are   pre-defined
  394.          constants  from  the  Turbo Pascal Crt unit.  The Box colors,
  395.          Border, and Shadow are global variables from the magic unit.
  396.               The Colors could just as easily have been represented by
  397.          numbers, as in the following example:
  398.  
  399.               program prog11a;
  400.               uses crt, magic;
  401.               begin
  402.                  sent[1] := 'How would you answer this question?';
  403.                  Dialog(-1,-1);
  404.                  BoxBack := 15;
  405.                  Border := 9;
  406.                  BoxText := 2;
  407.                  Shadow := 5;
  408.                  sent[1] := 'User typed:';
  409.                  sent[2] := Answer;
  410.                  GetAnyKey(-1,-1);
  411.               end.
  412.  
  413.          Lets find out what all the colors are:  Here  is  a  slightly
  414.          more complex program than any we have made so far:
  415.  
  416.               program prog12;
  417.               uses crt, magic;
  418.               begin
  419.                  border := white;
  420.                  BoxBack := black;
  421.                  CenterJustify := true;
  422.                  sent[1] := 'Type a number from 0 to 15.';
  423.                  dialog(-1,-1);
  424.                  repeat
  425.                     BoxText := number;
  426.                     if (BoxText  < 1) or (BoxText > 15) then boxtext := 15;
  427.                     sent[1] := 'The current color is #' + answer;
  428.                     sent[2] := 'Type a number from 0 to 15';
  429.                     sent[3] := 'or type 16 to exit';
  430.                     dialog(-1,-1);
  431.                  until answer = '16';
  432.               end.
  433.  
  434.          In  detail, prog12 does this: First, the Border color and the
  435.          BoxBack color are changed. CenterJustify will center text  in
  436.          the pop up boxes.
  437.             Then  a  one-line  dialog box appears. As soon as the user
  438.          answers the question in  this  dialog  box,  a  repeat  loop,
  439.          starts.  The  repeat  loop  changes  the BoxText color to the
  440.          "number" corresponding to what the user typed in  the  dialog
  441.          box.  "Number"  is  a function from the magic unit.  It takes
  442.          the Answer string (as returned by  Dialog)  and  converts  it
  443.          from  a  string  into an integer variable. That way it can be
  444.          assigned to BoxText and BoxText will be able to handle it.
  445.             Since  the only 'seeable' colors range from 1 to 15 (#0 is
  446.          black),  the  line  starting  with  'if'  repairs the boxtext
  447.          number if it not suitable.
  448.             BoxText is a byte variable (only values it can handle  are
  449.          0  through 255), but Answer is a string. Number fixes that by
  450.          becoming a integer compatible with BoxText.
  451.             Within the repeat loop a new box pops up containing  three
  452.          lines  of  text  written  in  the  color corresponding to the
  453.          number the user typed in the dialog box.
  454.             This all repeats until the user types "16".
  455.  
  456.          Let's make that program a little cleaner:
  457.  
  458.               program prog13;
  459.               uses crt, magic;
  460.               begin
  461.                  border := white;
  462.                  BoxBack := black;
  463.                  CenterJustify := true;
  464.                  sent[1] := 'Type a number from 0 to 15.';
  465.                  dialog(-1,-1);
  466.                  repeat
  467.                     BoxText := number;
  468.                     if (BoxText  < 1) or (BoxText > 15) then boxtext := 15;
  469.                     sent[1] := 'The current color is #' + answer;
  470.                     sent[2] := 'Type a number from 0 to 15';
  471.                     sent[3] := 'or type 16 to exit';
  472.                     dialog(-1,-1);
  473.                  until (answer = '16') or (u = #27);
  474.               end.
  475.  
  476.          There is only  one  small  change.  Can  you  spot  it?   The
  477.          second-from  last line now allows the user out of the loop by
  478.          typing "16" or by pressing the [Esc] key which is Ascii  #27.
  479.          This  is  because Dialog uses the global character u to build
  480.          the Answer string. U always contains the character  value  of
  481.          the last character entered, which in the case of pressing the
  482.          [Esc] key would be #27.
  483.  
  484.          Prog14  will  be our first program that does something useful
  485.          in the real world.  It will produce the square of an integer.
  486.          I know  that's  not  much.  You  paid  around  $1000 for your
  487.          computer, but your $5  calculator can do  squares, and it can
  488.          even do it  with  floating  point numbers, which this example
  489.          can't.  The  importang thing is, once you learn this, you can
  490.          build on this program.
  491.  
  492.               program prog14;
  493.               uses crt, magic;
  494.               var
  495.                  thing : word;
  496.               begin
  497.                  repeat
  498.                     sent[1] := 'Type a number to be squared';
  499.                     sent[2] := 'or press [Esc] to end program';
  500.                     dialog(3,3);
  501.                     if u <> #27 then
  502.                     begin
  503.                        thing := number * number;
  504.                        str(thing,answer);
  505.                        sent[1] := 'The square is ' + answer;
  506.                        GetAnyKey(40,15);
  507.                        XClear;
  508.                     end;
  509.                  until (u = #27);
  510.               end.
  511.  
  512.          Prog14 introduces two new concepts. First we have a line that
  513.          contains  "var." This line is found before the first begin in
  514.          any procedure, or before the body of a program but after  the
  515.          uses  clause. The lines that follow "var" are "user-declared"
  516.          variables. If they are declared before the main body  of  the
  517.          program they are "global," usable throughout the program.  If
  518.          they  are  declared  within a function or procedure, they are
  519.          usable only by that function or procedure.
  520.             In this case, we have declared, "thing  :  word."  on  the
  521.          left  of  the  colon (notice no = sign) is any combination of
  522.          letters and numbers and "_"  allowed  by  Turbo  Pascal  (see
  523.          manual). On the right of the colon is the type of variable it
  524.          is.  A  word is a integer number with a positive value from 0
  525.          to approximately 64000. Other common types appointed by Turbo
  526.          Pascal are integer (approx  value  -32000  to  +32000),  real
  527.          (floating  point  number),  byte  (0 to 255), char (Any ASCII
  528.          character),  string  (an  array,  or  group  of  characters),
  529.          pointer  (indicating  the  starting location of a variable of
  530.          any type stored in memory) and an array (a group  of  any  of
  531.          these  items).  Additionally, you can make up your own types,
  532.          composed of one or more of these basic types  in  a  mixture.
  533.          For more information about all this, watch the Var section of
  534.          the  programs  that  follow  in  this  tutorial, and see your
  535.          Borland manuals.
  536.              Furthermore, we  introduced  "str"  which  is  a  Borland
  537.          procedure  to  convert  a  numeric  variable  into  a  string
  538.          representing that number in text.
  539.              This program is easy to crash. All  you  have  to  do  is
  540.          pick  a  number  that's  square  is  more than the range of a
  541.          "word" type variable. (64000)
  542.              There are a couple more new things here, but if  you  are
  543.          sharp,  you  probably already picked them out. One is the "*"
  544.          which is computer programming talk for "multiply". The  other
  545.          is the "<>" which means "not equal to."
  546.              This  program will be quite confusing, it would have been
  547.          confusing to me for the first year or so  that  I  was  using
  548.          Turbo  Pascal,  so you might want to study it carefully. Once
  549.          you understand what everything does, try making  changes  and
  550.          see  if the do what you would expect. Once you get it, you're
  551.          well on your way to writing custom programs.
  552.  
  553.              Most of prog15 is similar to the last, but  this  one  is
  554.          for converting inches to millimeters. Try it and you'll see a
  555.          surprise.
  556.  
  557.               program prog15;
  558.               uses crt, magic;
  559.               var
  560.                  millimeters : real;
  561.               begin
  562.                  repeat
  563.                     sent[1] := 'Enter a number of inches';
  564.                     sent[2] := 'or press [Esc] when done';
  565.                     dialog(2,2);
  566.                     if u <> #27 then
  567.                     begin
  568.                        millimeters := number * 25.4;
  569.                        str(millimeters,answer);
  570.                        sent[1] := 'That would be ' + answer + ' millimeters';
  571.                        GetAnyKey(30,20);
  572.                        xclear;
  573.                     end;
  574.                  until u = #27;
  575.               end.
  576.  
  577.               The  surprise  is  in  the way Turbo Pascal handles real
  578.          variables when converted to string variables. Unless you  add
  579.          specific formatting commands, you'll get scientific notation.
  580.          So,   prog15a  has  a  small  change  in  the  str  procedure
  581.          parameters,  specifically,  "millimeters"  is  followed  with
  582.          ":1:0."  See  your  Borland  books  for more information, but
  583.          basically, if the first integer is anything less than 8, then
  584.          up  to  8  digits  will  be  displayed.  The  second  integer
  585.          determines  how  many  digits after the decimal point will be
  586.          considered in the string. For monetary notations, your second
  587.          integer would typically be 2, for cents.
  588.  
  589.               program prog15a;
  590.               uses crt, magic;
  591.               var
  592.                  millimeters : real;
  593.               begin
  594.                  repeat
  595.                     sent[1] := 'Enter a number of inches';
  596.                     sent[2] := 'or press [Esc] when done';
  597.                     dialog(2,2);
  598.                     if u <> #27 then
  599.                     begin
  600.                        millimeters := number * 25.4;
  601.                        str(millimeters:1:0,answer);
  602.                        sent[1] := 'That would be ' + answer
  603.                           + ' millimeters';
  604.                        GetAnyKey(30,20);
  605.                        xclear;
  606.                     end;
  607.                  until u = #27;
  608.               end.
  609.  
  610.               Program 16 converts Dupers from the country  Xanopieland
  611.          to United States Dollars.
  612.  
  613.               program prog16;
  614.               uses crt, magic;
  615.               var
  616.                  dollars : real;
  617.               begin
  618.                  centerjustify := true;
  619.                  sent[1] := 'How many Dupers?';
  620.                  dialog(-1,-1);
  621.                  dollars := number * 0.7143; {current duper
  622.                                              conversion rate}
  623.                  str(dollars:1:2,answer);
  624.                  sent[3] := '$' + answer;
  625.                  sent[2] := '';
  626.                  sent[1] := 'You own this much Xanopieland money:';
  627.  
  628.                    (* notice that sent[3] is assigned above *)
  629.  
  630.                  sent[4] := '';
  631.                  sent[5] := 'Press any key to end program...';
  632.                  GetAnyKey(-1,-1);
  633.               end.
  634.  
  635.          Prog16 introduces comments. There are two ways  you  can  put
  636.          comments into your source code that won't affect the way your
  637.          program  is  compiled.  One  is  to  place  it  between curly
  638.          brackets {} and the other way is to use  (*  and  *)  as  the
  639.          borders  of  comments. Comments can extend over several lines
  640.          as long as the beginning is marked with { or (* and  the  end
  641.          is  marked  with  the matching } or *). You can even nest one
  642.          type within another:
  643.                        {comment (* within a comment *)}
  644.              No  matter how many comments you put in your source code,
  645.          there will be no change in the compiled program's size or run
  646.          time speed.
  647.              Comments can be very important for you or for others that
  648.          have to figure out your programs a long time after  you  have
  649.          created them.
  650.              Prog16  also  illustrates that Turbo Pascal is not at all
  651.          fussy about white space. The only place white  space  matters
  652.          is within strings. The same program can be written this way:
  653.  
  654.          program prog16a; uses crt, magic; var dollars : real; begin
  655.          centerjustify := true; sent[1] := 'How many Dupers?';
  656.          dialog(-1,1); dollars := number * 0.7143; {current duper}
  657.          {conversion rate} str(dollars:1:2,answer); sent[3] := '$' +
  658.          answer; sent[2] := ''; sent[1] :=
  659.          'You own this much Xanopieland money:'; (* notice that
  660.          sent[3] is assigned above *) sent[4] := ''; sent[5] :=
  661.          'Press any key to end program...'; GetAnyKey(-1,1); end.
  662.  
  663.          Program 16a is just as easy for the  compiler  to  read,  but
  664.          much harder for humans to read!
  665.  
  666.          Let's  make one more improvement in prog16. In prog16b, we'll
  667.          straighten out the way Dupers can be  entered.  The  standard
  668.          dialog  box is as wide as the widest sent[] and therefore the
  669.          answer can be that long. What if you want to limit  the  user
  670.          to  a  4-digit  answer, for instance? The following technique
  671.          works well for use with filling in database forms:
  672.  
  673.               program prog16b;
  674.               uses crt, magic;
  675.               var
  676.                  dollars : real;
  677.               begin
  678.                  centerjustify := true;
  679.                  sent[1] := 'How many Dupers?';
  680.                  sent[2] := ' '; {must be at least one char}
  681.                  pop(-1,-1);
  682.                  textcolor(BoxText);
  683.                  textbackground(BoxBack);
  684.                  answer := XReadLn(38,12,4);
  685.                  restore;
  686.                  dollars := number * 0.7143;
  687.                  str(dollars:1:2,answer);
  688.                  sent[3] := '$' + answer;
  689.                  sent[2] := '';
  690.                  sent[1] := 'You own this much Xanopieland money:';
  691.                  sent[4] := '';
  692.                  sent[5] := 'Press any key to end program...';
  693.                  GetAnyKey(-1,-1);
  694.               end.
  695.  
  696.          Can you spot the differences? This program does not depend on
  697.          Dialog.  Instead,  we  pop  up  a  box with "pop," which is a
  698.          simple procedure that remembers what's on  the  screen,  then
  699.          puts  a  box  on  the screen. Since pop will use only as many
  700.          sent[]s as have text, sent[2] is ' ', or  one  blank,  so  it
  701.          will  be  included  in  pop's box.  This will give the user a
  702.          line within the box on which to type the answer.
  703.             Then  the  current text color and background color are set
  704.          to the same as the colors within the box,  so  that  XReadLn,
  705.          will  work  in  the  proper colors. XReadln is like the Turbo
  706.          Pascal ReadLn procedure but with three  differences.  XReadLn
  707.          accepts  mouse  control  (left  mouse button is like pressing
  708.          [Enter] and right button is like [Esc]), XReadLn requires two
  709.          integers to designate the screen coordinates at which it will
  710.          echo the text typed by the user, and a  third  integer  which
  711.          limits how long a string the user is allowed to type.
  712.              Dialog  knows  when  the  user  is done, and restores the
  713.          screen and disappears, but pop doesn't know what  is  wanted,
  714.          so  stays  on  the  screen  until a specific call to Restore,
  715.          which wipes it out and replaces the previous screen image.
  716.  
  717.          Prog17 shows many new techniques. It is the  Universal  Money
  718.          Converter.  For  simplicity,  only the first menu entry has a
  719.          procedure installed. Run this program to see  what  it  does,
  720.          then  study  the  source  code  to see how it does it. From a
  721.          practical point of view, you can see that with modifications,
  722.          this could be used for real money from  real  countries.  For
  723.          that  matter,  the  same  program  could be modified for many
  724.          purposes.  How  about  a  universal  metric  converter   that
  725.          converts lengths, weights, temperatures, etc?
  726.             (NOTE:  When  I  first roughed out this tutorial, I got to
  727.          thinking about the previous sentence, and an idea  was  born.
  728.          It  is  now  complete  and  being  distributed  as shareware.
  729.          Perhaps you've seen it, THE  UNIVERSAL  CONVERTER.  This  new
  730.          program  performs  over  600 useful calculations and it makes
  731.          extensive use of Pascal Magic!)
  732.  
  733.               program prog17;
  734.               uses crt, magic;
  735.               var
  736.                  dollars : real;
  737.  
  738.               procedure xano;
  739.               begin
  740.                  sent[1] := 'How many Xanopieland Dupers?';
  741.                  sent[2] := ' '; {must be at least one char}
  742.                  pop(-1,-1);
  743.                  textcolor(BoxText);
  744.                  textbackground(BoxBack);
  745.                  answer := XReadLn(38,12,4);
  746.                  restore;
  747.                  dollars := number * 0.7143;
  748.                  str(dollars:1:2,answer);
  749.                  sent[3] := '$' + answer;
  750.                  sent[2] := '';
  751.                  sent[1] := 'You own this much Xanopieland money:';
  752.                  sent[4] := '';
  753.                  sent[5] := 'Press any key to continue...';
  754.                  GetAnyKey(-1,-1);
  755.               end;
  756.  
  757.               begin  {main}
  758.                  centerjustify := true;
  759.                  sent[1] := 'Universal Money Converter';
  760.                  pop(25,2);
  761.                  mc := 1;
  762.                  repeat
  763.                     sent[1] := 'Xanopieland';
  764.                     sent[2] := 'Braze Island';
  765.                     sent[3] := 'Nomania';
  766.                     sent[4] := 'Grazille';
  767.                     sent[5] := 'Exit to Dos';
  768.                     menu(-1,-1);
  769.                     if u = #13 then
  770.                     begin
  771.                        if mc = 1 then xano;
  772.  
  773.                    (*  if mc = 2 then braze;
  774.                        if mc = 3 then nomania;
  775.                        if mc = 4 then Grazille; *)
  776.                      end;
  777.                  until (u = #13) and (mc = 5);
  778.                  CleanUp;
  779.               end.
  780.  
  781.          The most noticeable change  is  the  use  of  a  sub-routine,
  782.          called  a  "procedure."  And Pascal seems kind of backward at
  783.          first - the main program is the bottom-most  thing,  and  the
  784.          procedure(s)  are at the top. In Pascal, it must be this way.
  785.          Any  procedure  or  function  that  is  called  from  another
  786.          procedure  or  function,  or  from  the main program, must be
  787.          above  it in the source code. Actually, there are ways around
  788.          this (see Forward declaration in your Borland  manuals),  but
  789.          for now, we'll keep it simple.
  790.             The procedure Xano is called only when  the  user  selects
  791.          the first menu entry.
  792.             Now, let's look at the main program to see exactly what it
  793.          does.  You  know  CenterJustify.  It  makes  all  the sent[]s
  794.          centered within the pop-up boxes.
  795.             Then a box pops near the top of the screen with the  text,
  796.          "Universal  Money  Converter." Then we have a funny line, "mc
  797.          := 1." I'll explain that one in a minute.
  798.             Within the repeat loop are 5 sent[]s and  a  call  to  the
  799.          magic  procedure  "menu". Menu is like the other pop-up boxes
  800.          you are familiar with, but it is a light-bar menu. It  allows
  801.          the  user  to  highlight any one of the sent[]s by moving the
  802.          mouse or using the arrow keys. When the user presses [Enter],
  803.          [Esc] or a mouse button, the menu box  disappears.  A  global
  804.          integer  variable,  "mc" is assigned the number of the sent[]
  805.          that was highlighted when the menu box disappears. So if  the
  806.          user has highlighted Nomania (sent[3]), then pressed [Enter],
  807.          then mc will equal 3.
  808.             And  after  the menu box disappears, the next line of code
  809.          will be executed, which happens to be "if mc = 1 then  xano."
  810.          Well,  if the user selected Nomania, then mc is not 1 and the
  811.          procedure xano will not be run. mc = 3, but the line, "if  mc
  812.          =  3  then  nomania" is commented out, so nothing will occur.
  813.          However, if the user had selected Xanopieland, then mc  would
  814.          be  1  and the procedure xano would be executed. And you know
  815.          what that does, it is the same as prog16. If the user  should
  816.          select  sent[5]  then  mc will be 5 and the until clause will
  817.          then allow the program to end.  The  last  procedure  in  the
  818.          program  is  CleanUp  which restores everything to the way it
  819.          was before the program started. It resets the screen  colors,
  820.          clears  the  screen  and  the  program terminates gracefully.
  821.          CleanUp should be used at the end of every program. It has  a
  822.          very  specific purpose here. Remember the one-line pop at the
  823.          beginning of the program? It held a picture of  what's  under
  824.          that  box  in  memory  and  is still holding it until calling
  825.          CleanUp. We never "Restore"d the first "pop".
  826.              Now about that line "mc := 1." Without  this  line,  when
  827.          menu  is  first  started,  it  doesn't  know  which sent[] to
  828.          highlight. You must tell it. If you forget to assign a  value
  829.          to  mc  before  calling  a  menu,  then a random item will be
  830.          highlighted. Notice that "mc := 1" is before the repeat loop.
  831.          This is because, once the repeat loop starts, the user may be
  832.          most comfortable seeing the menu pop-up  with  the  highlight
  833.          where  it  was last located rather than on the top item every
  834.          time.
  835.  
  836.          Prog18 is the same as the last one, except we use  DoubleMenu
  837.          instead  of  Menu.  Everything  is  the same, but the menu is
  838.          shorter and wider, allowing for situations where you may have
  839.          lots of menu choices. You can  use  up  to  36  sent[]s  with
  840.          DoubleMenu.
  841.  
  842.               program prog18;
  843.               uses crt, magic;
  844.               var
  845.                  dollars : real;
  846.  
  847.               procedure xano;
  848.               begin
  849.                  sent[1] := 'How many Xanopieland Dupers?';
  850.                  sent[2] := ' '; {must be at least one char}
  851.                  pop(-1,-1);
  852.                  textcolor(BoxText);
  853.                  textbackground(BoxBack);
  854.                  answer := XReadLn(38,12,4);
  855.                  restore;
  856.                  dollars := number * 0.7143;
  857.                  str(dollars:1:2,answer);
  858.                  sent[3] := '$' + answer;
  859.                  sent[2] := '';
  860.                  sent[1] := 'You own this much Xanopieland money:';
  861.                  sent[4] := '';
  862.                  sent[5] := 'Press any key to continue...';
  863.                  GetAnyKey(-1,-1);
  864.               end;
  865.  
  866.               begin  {main}
  867.                  centerjustify := true;
  868.                  sent[1] := 'Universal Money Converter';
  869.                  pop(25,2);
  870.                  mc := 1;
  871.                  repeat
  872.                     sent[1] := 'Xanopieland';
  873.                     sent[2] := 'Braze Island';
  874.                     sent[3] := 'Nomania';
  875.                     sent[4] := 'Grazille';
  876.                     sent[5] := 'Exit to Dos';
  877.                     doublemenu(-1,-1);
  878.                     if u = #13 then case mc of
  879.                        1 : xano;
  880.                     (* 2 : brace;
  881.                        3 : nomania;
  882.                        4 : grazille; *)
  883.                     end;
  884.                  until (u = #13) and (mc = 5);
  885.               end.
  886.  
  887.          In  prog18 we have also cleaned up the multiple if statements
  888.          by  using  a  "case"  statement.  But,  there  are  still  no
  889.          procedures  written for 3 of the 5 menu choices, so these are
  890.          commented out.
  891.  
  892.          Prog19 adds another  case  statement  allowing  the  user  to
  893.          press  a key corresponding to the first letter of a menu item
  894.          and then that procedure will be run directly.
  895.  
  896.               program prog19;
  897.               uses crt, magic;
  898.               var
  899.                  dollars : real;
  900.  
  901.               procedure xano;
  902.               begin
  903.                  sent[1] := 'How many Xanopieland Dupers?';
  904.                  sent[2] := ' '; {must be at least one char}
  905.                  pop(-1,-1);
  906.                  textcolor(BoxText);
  907.                  textbackground(BoxBack);
  908.                  answer := XReadLn(38,12,4);
  909.                  restore;
  910.                  dollars := number * 0.7143;
  911.                  str(dollars:1:2,answer);
  912.                  sent[3] := '$' + answer;
  913.                  sent[2] := '';
  914.                  sent[1] := 'You own this much Xanopieland money:';
  915.                  sent[4] := '';
  916.                  sent[5] := 'Press any key to continue...';
  917.                  GetAnyKey(-1,-1);
  918.               end;
  919.  
  920.               begin  {main}
  921.                  centerjustify := true;
  922.                  sent[1] := 'Universal Money Converter';
  923.                  pop(25,2);
  924.                  mc := 1;
  925.                  repeat
  926.                     sent[1] := 'Xanopieland';
  927.                     sent[2] := 'Braze Island';
  928.                     sent[3] := 'Nomania';
  929.                     sent[4] := 'Grazille';
  930.                     sent[5] := 'Exit to Dos';
  931.                     doublemenu(-1,-1);
  932.                     if (u = #13) then case mc of
  933.                        1 : xano;
  934.                     (* 2 : brace;
  935.                        3 : nomania;
  936.                        4 : grazille; *)
  937.                     end
  938.                     else
  939.                     case upcase(u) of
  940.                        'X' : xano;
  941.                     (* 'B' : braze;
  942.                        'N' : nomania;
  943.                        'G' : grazille; *)
  944.                        'E' : begin
  945.                                 mc := 5;
  946.                                 u := #13;
  947.                               end;
  948.                     end;
  949.                  until (u = #13) and (mc = 5);
  950.               end.
  951.  
  952.          There are opportunities for bugs here. You want to make  sure
  953.          u = #13 (the [Enter] key) before allowing the first "case" to
  954.          execute,  because  otherwise,  a procedure may run twice in a
  955.          row if the user presses a character  key,  first  when  mc  =
  956.          whatever,  then  then  when u = 'whatever'. Also make sure to
  957.          put the second case characters in  single  quote  marks.  And
  958.          last,  notice  the  "upcase(u)."  Without this the user would
  959.          have to press the shift key to get the desired result. Upcase
  960.          converts u into a capital letter.
  961.  
  962.          Prog20 is going to be a big, but very special program because
  963.          it  will  be  something  you'll use everyday.  Run it and see
  964.          what it does, then study the source code to understand it.
  965.  
  966.               program prog20;
  967.               uses crt, magic;
  968.  
  969.               procedure extkey;               (* 1 *)
  970.               var
  971.                  tempstr : string[3];
  972.                  ekey : boolean;
  973.               begin
  974.                  XClear;                         (* 8 *)
  975.                  sent[1] := 'Press any key to see it''s extended code';
  976.                  sent[2] := 'Press ''Q'' when done.';
  977.                  pop(18,3);
  978.                  sent[1] := ' ';    (* 9 *)
  979.                  sent[2] := '';
  980.                  repeat
  981.                     ekey := false;
  982.                     GetAnyKey(-1,-1);
  983.                     if u = #0 then
  984.                     begin
  985.                        sent[1] := '#0 + ';
  986.                        u := readkey;
  987.                        ekey := true;
  988.                     end;
  989.                     case u of
  990.                        #13 : answer := ' ';   (*  10  *)
  991.                        #8  : answer := ' ';
  992.                        #10 : answer := ' ';
  993.                        #7  : answer := ' ';
  994.                        else answer := u;
  995.                     end; {case}
  996.                     str(ord(u),tempstr);
  997.                     sent[1] := sent[1] + answer + ' (#' + tempstr + ')';
  998.                  until (upcase(u) = 'Q') and (ekey = false);
  999.                  XClear;
  1000.               end;  {procedure ExtKey}
  1001.  
  1002.               procedure asciichart;
  1003.               var
  1004.                  x,y : byte;            (*  3  *)
  1005.                  temp : integer;
  1006.               begin
  1007.                  textcolor(white); textbackground(black);
  1008.                  x := 1;
  1009.                  y := 1;
  1010.                  clrscr;
  1011.                  for temp := 0 to 255 do
  1012.                  begin
  1013.                     u := chr(temp);   (* 4 *)
  1014.                     gotoxy(x,y);      (* 5 *)
  1015.                     write(' ');
  1016.                     if temp < 10 then write(' ');
  1017.                     if temp < 100 then write(' ');
  1018.                     if (temp <> 7) and (temp <> 8) and (temp <> 10)
  1019.                      and (temp <> 13) and (temp <> 27)   (* 11 *)
  1020.                      then write(temp,'=',u,' ')
  1021.                     else write(temp,'=');
  1022.                     inc(y);     (* 6 *)
  1023.                     if y > 25 then
  1024.                     begin
  1025.                        y := 1;
  1026.                        x := x + 7;
  1027.                     end;
  1028.                  end; {end of for 0 to 255 loop}
  1029.                  WaitForUser;
  1030.                  xclear;      (*  7  *)
  1031.               end; {procedure Asciichart}
  1032.  
  1033.               begin {main}
  1034.                  centerjustify := true;
  1035.                  mc := 1;
  1036.                  repeat
  1037.                     BoxBack := red;
  1038.                     sent[1] := 'Programmer''s Tools';
  1039.                     sent[2] := 'Copyright 1991, Freeware by Another Company';
  1040.                     pop(18,2);
  1041.                     BoxBack := green;
  1042.                     sent[1] := 'ASCII Chart';
  1043.                     sent[2] := 'Extended Keys';
  1044.                     sent[3] := 'Quit';
  1045.                     menu(-1,-1);
  1046.                     if u = #13 then
  1047.                     case mc of
  1048.                        1 : AsciiChart;            (* 2 *)
  1049.                        2 : ExtKey;
  1050.                     end;
  1051.                  until (u = #13) and (mc = 3);
  1052.                  CleanUp;
  1053.               end.
  1054.  
  1055.          I've tagged this file with note numbers surrounded by (*  and
  1056.          *).  Note 1) Don't look here to start reading a program, this
  1057.          is  merely  a  sub-routine.  Go  way down to the main program
  1058.          block, where it says "{main}" to get a feel for what's  going
  1059.          on.
  1060.              Looking at the overall program you'll see that  there  is
  1061.          the  main  program  block  and  two  procedures, which may be
  1062.          called from the case statement in the main block.
  1063.  
  1064.          Note 2) If the user  selects  the  first  menu  item,  "ASCII
  1065.          Chart"  then  MC will be 1, and the AsciiChart procedure will
  1066.          be called. Now let's go up and take a look at that procedure.
  1067.  
  1068.          Note 3) Here are some variables being  declared  within  this
  1069.          procedure.  They are not available to the main program. X and
  1070.          y  are bytes, they can hold a value of from 0 to 255. Temp is
  1071.          an integer, with a possible value of from  approx  -32000  to
  1072.          +32000. If you look down a few lines, you'll see that x and y
  1073.          are  specifically set to 1. In Pascal, as in most programming
  1074.          languages, the act of declaring a variable doesn't set it  to
  1075.          0  or  any other value. Unless specifically set to something,
  1076.          it's value will be random. In this procedure, the  values  of
  1077.          x and y need to start with 1.
  1078.  
  1079.          Note  4) We are in a "for" loop which as it is set up in this
  1080.          program will start with temp defined as 0  and  the  contents
  1081.          of  the  loop  (between the "begin" and "end" will repeat 255
  1082.          times, and each time, the value of temp will be increased  by
  1083.          1.
  1084.             The  first  thing  that  happens in this loop is that u, a
  1085.          global  char  variable,  is  set  to  the   ASCII   character
  1086.          represented  by  the value of temp. This is done by the Turbo
  1087.          Pascal function "chr."
  1088.  
  1089.          Note 5) The  next  thing  that  happens  in  this  loop  that
  1090.          repeats 255 times is "gotoxy." Gotoxy moves the cursor to the
  1091.          coordinates  in  the  parentheses.  Then,  with  close study,
  1092.          you'll figure out what  is  written  to  the  screen  by  the
  1093.          program in the several following lines of code.
  1094.             Following  this,  are  a  few  lines  to make columns on a
  1095.          single screen rather than simply scrolling  down  255  lines.
  1096.          I'll  let  you figure out how that's accomplished by studying
  1097.          the code.
  1098.  
  1099.          Note  6)  This  note  calls  your  attention  to  the   line,
  1100.          "inc(y)."  Inc adds 1 to an integer value. It is like saying,
  1101.          "y := y + 1. By doing this, when the next  iteration  of  the
  1102.          loop   occurs,  and  the  gotoxy  is  encountered,  the  next
  1103.          character will be written one line below  the  last,  because
  1104.          of y being one number higher.
  1105.  
  1106.          Note  7)  After  the  255  executions  of  the  for loop, the
  1107.          program calls the magic procedure  WaitForUser,  which  waits
  1108.          for  the  user  to  press  a key or click a mouse button. The
  1109.          next line is XClear, which clears the screen  in  preparation
  1110.          to return to the main program.
  1111.  
  1112.          Note  8)  is  way  up high in the code, in the top procedure.
  1113.          This procedure, ExtKey is the one which pops up the ASCII and
  1114.          Extended Key information in a little window for each key that
  1115.          is pressed. First thing this  procedure  does  is  clear  the
  1116.          screen  again.  Then  it makes a box with a couple of sent[]s
  1117.          explaining, "Press any key to see it''s extended  code,"  and
  1118.          "Press  ''Q''  when  done."  Look  at  all those single quote
  1119.          marks! There are two of them after in it''s, and  two  single
  1120.          quote marks in a row on either side of the ''Q''. No, they're
  1121.          not   typographical   errors.   This   is  how  Turbo  Pascal
  1122.          differentiates between the beginning and  end  of  a  literal
  1123.          string, and a string containing a ' in it. When there are two
  1124.          ''s, Pascal prints it on the screen as a single '. When there
  1125.          is just one ' in the source code, Turbo Pascal thinks you are
  1126.          trying to mark the beginning or end of a literal string.
  1127.  
  1128.          Note  9) The first time the ExtKey procedure runs, as you may
  1129.          recall, a little box containing nothing  appears,  until  you
  1130.          press  a  key to fill it. Sent[1] has to be something, or the
  1131.          program will think there are no sent[]s at all, so sent[1] is
  1132.          a one-character string containing a space.  sent[2]  must  be
  1133.          specifically   rewritten  as  a  string  containing  nothing,
  1134.          because the preceding pop had  used  two  sent[]s,  and  the
  1135.          information  in  sent[]s  is not cleared after a call to pop,
  1136.          as it would be in pop-up boxes that  automatically  disappear
  1137.          after they are done.
  1138.  
  1139.          Notes  10  and  11)  Some  characters,  when  written  to the
  1140.          "screen" do funny things.   #8  is  the  backspace  character
  1141.          which  will  actually  back up the cursor and cause something
  1142.          else to be overwritten.  #13 is a carriage return and #10  is
  1143.          a line feed, which would screw up a chart or anything you try
  1144.          to  display normally. #7 goes "beep!" So such characters must
  1145.          specifically eliminated if you try to  write  them  literally
  1146.          to the screen.
  1147.  
  1148.          This  is  an  excellent program to study in detail.  A really
  1149.          good way to understand it is to modify it.  Experiment.  Make
  1150.          changes,  and  see  if when you run the program, your changes
  1151.          act as you had expected. See  if  you  can  improve  on  this
  1152.          program  or  add  new  features. If you can understand all of
  1153.          this, you are well on your way to being a GOOD programmer.
  1154.  
  1155.          Prog21 is derived from  prog20.  It  is  a  demonstration  of
  1156.          writing  to a disk file. The object of this program is to put
  1157.          a column of ASCII equivalents in a text file, so you can  use
  1158.          it with your word processor, etc. Run prog21, then go look at
  1159.          the  file  called ASCII.TXT with the Turbo Pascal IDE or your
  1160.          favorite word processor.  Be  aware,  prog21  is  very  slow,
  1161.          requiring several seconds to run its course.
  1162.  
  1163.               program prog21;
  1164.               uses crt,magic;
  1165.               var
  1166.                 temp : integer;
  1167.                 tempstr : string;
  1168.               begin
  1169.                  NameOutFile('Ascii.txt');
  1170.                  for temp := 0 to 255 do
  1171.                  begin
  1172.                     str(temp,tempstr);
  1173.                     tempstr := tempstr + ' = ' + chr(temp);
  1174.                     FileWriteLn(tempstr);
  1175.                  end;
  1176.               end.
  1177.  
  1178.          There  are  two special items in the magic unit, "InFile" and
  1179.          "OutFile." InFile is used to get text in from  the  disk  and
  1180.          use   it   within  your  program.  OutFile  is  used  to  put
  1181.          information out to the disk. Essentially, these are  pathways
  1182.          to  disk files. You must give them names that will be used in
  1183.          the disk directory. As usual with  disk  files,  these  names
  1184.          must  be  DOS-legal,  with  up  to  8  characters, optionally
  1185.          followed by a period and up to a  three-character  extension.
  1186.          Drive  designator  and sub-directory designations can precede
  1187.          file names.
  1188.  
  1189.             So we would use OutFile to convey information to the disk.
  1190.          The first operation in prog21 is to associate a disk filename
  1191.          with outfile, using "NameOutFile."
  1192.             Then a for loop creates  a  string,  "tempstr"  containing
  1193.          each  ASCII  number  and  the  character  represented by that
  1194.          number. The line in  this  loop,  "FileWriteLn"  writes  this
  1195.          tempstr to the disk.
  1196.             There  is  another procedure called FileWrite which writes
  1197.          strings to disk, but does not put  each  one  on  a  separate
  1198.          line.  This  follows  the  convention of Turbo Pascal's Write
  1199.          and Writeln.
  1200.             If you have named a file that does not yet exist on  disk,
  1201.          it  will  be  created  automatically  with  the first call to
  1202.          FileWriteLn or FileWrite. If the  file  already  exists,  the
  1203.          string  passed with FileWriteLn or FileWrite will be appended
  1204.          to the end of the file.
  1205.             You'll  notice  two things about FileWriteLn, one iis that
  1206.          it  is  very  slow.   FileWriteLn   is   nice,   because   it
  1207.          automatically  does  several  things  that you would normally
  1208.          have to write separately into your program, but that's why it
  1209.          is slow.
  1210.             The  other  thing you'll see when you look at the finished
  1211.          file.  Some of the characters do funny things when written to
  1212.          a file, causing a sort of misalignment. These are things like
  1213.          line feed (#10) and Bell (#7), which beeps if read by the DOS
  1214.          type command.
  1215.  
  1216.          Prog22 is a variation of the previous  program  that  handles
  1217.          writing  to  file  more  manually, resulting in a much faster
  1218.          program, and eliminates the funny characters.
  1219.  
  1220.               program prog22;
  1221.               uses crt,magic;
  1222.               var
  1223.                  temp : integer;
  1224.                  tempstr : string;
  1225.                  outfile : text;
  1226.               begin
  1227.                  assign(outfile,'Ascii.txt');
  1228.                  rewrite(outfile);
  1229.                  for temp := 0 to 255 do
  1230.                  begin
  1231.                     str(temp,tempstr);
  1232.                     tempstr := tempstr + ' = ';
  1233.                     if (temp <> 7) and (temp <> 10) and (temp <> 13)
  1234.                     and (temp <> 26) then tempstr := tempstr + chr(temp);
  1235.                     writeln(outfile,tempstr);
  1236.                  end;
  1237.                  close(outfile);
  1238.               end.
  1239.  
  1240.          Cleaner and faster, eh?  I won't go  into  the  specifics  of
  1241.          file  handling  here, it is all well documented in your Turbo
  1242.          Pascal manuals. There are three types of files you  can  work
  1243.          with,  with  text  files  being  the  most  often used by new
  1244.          programmers, and there are many things you can do with  files
  1245.          besides  simple  reading  and  writing  of  strings. For that
  1246.          matter, there's a whole bunch  of  things  you  can  do  with
  1247.          strings, but all that is well beyond the scope of this humble
  1248.          tutorial.
  1249.  
  1250.          The  compliment of FileWriteLn is FileReadLn. Prog23 shows it
  1251.          in operation, using the previously created Ascii.txt.
  1252.  
  1253.               program prog23;
  1254.               uses crt,magic;
  1255.               var
  1256.                  tempstr : string;
  1257.               begin
  1258.                  clrscr;
  1259.                  NameInFile('Ascii.txt');
  1260.                  repeat
  1261.                     tempstr := FileReadLn;
  1262.                     writeln(tempstr);
  1263.                  until problem;
  1264.                  WaitForUser;
  1265.                  CleanUp;
  1266.               end.
  1267.  
  1268.          Not very elegant, since  the  stuff  scrolls  right  off  the
  1269.          screen,  but  you  get  the general idea. Notice the 4th line
  1270.          from the bottom: "until problem".  This introduces  something
  1271.          very  excellent  about  the magic unit. It is always watching
  1272.          for mistakes. If you ask most of the functions and procedures
  1273.          in the magic unit to do something that can't be done, they do
  1274.          not crash the program. Instead, they handle  the  problem  as
  1275.          gracefully  as  possible and set a global boolean variable to
  1276.          true. If there is no problem with your use of the function or
  1277.          routine problem is false.
  1278.             In this case, if you try to read beyond  the  end  of  the
  1279.          file,  FileReadLn  turns problem to true, and this particular
  1280.          program's repeat until loop falls through,  and  the  program
  1281.          ends.  If  you  forced the issue or wrote a program that does
  1282.          not regard "problem" then  any  subsequent  attempts  to  use
  1283.          FileReadLn would simply assign #0 to tempstr.
  1284.              In  Turbo  Pascal, files that are read from or written to
  1285.          must  first  be  opened,  the  operation(s)  performed,  then
  1286.          closed.   FileWrite   and   FileWriteLn   handle   all   this
  1287.          automatically, but FileRead and FileReadLn cannot, because if
  1288.          you were to make subsequent calls to these and they did  open
  1289.          and  close  the file each time, each time you read, you would
  1290.          always get the first line in the file, since opening a  file,
  1291.          resets it to the beginning.
  1292.              So from the first time you read the file with FileRead or
  1293.          FileReadLn,  InFile  remains open. It should be closed before
  1294.          the program ends, and the best way to do that is to call  the
  1295.          very  standard  procedure,  "CleanUp"  which  is specifically
  1296.          designed to be the last line in any program.  It  closes  all
  1297.          open  files,  resets  the  video  mode, clears the screen and
  1298.          frees up memory. It never hurts to have this line at the  end
  1299.          of any program, and it is essential at the end of some.
  1300.              If  you  have read several lines in infile, then you want
  1301.          to start over at the top, do this: "reset(infile)."
  1302.  
  1303.          Prog24 explores graphics a bit. Compile it, run it, study it.
  1304.  
  1305.               program prog24;
  1306.               uses crt, video, magic;
  1307.               begin
  1308.                  sent[1] := 'This is text mode';
  1309.                  GetAnyKey(-1,-1);
  1310.                  BestVideo;
  1311.                  sent[1] := 'This is a graphics mode';
  1312.                  GetAnyKey(-1,-1);
  1313.                  CleanUp;
  1314.               end.
  1315.  
  1316.          As you can see, it is quite simple.  There are only  two  new
  1317.          things  in this program.  Can you spot them? The first is the
  1318.          use of a new unit, "Video." The second is a procedure  called
  1319.          "BestVideo."  BestVideo  is a procedure that figures out what
  1320.          type of monitor you have, then sets up the program to run  on
  1321.          your graphics card.
  1322.             And there is a special surprise. Those  of  you  who  have
  1323.          done  some  graphics work in Turbo Pascal will recognize it's
  1324.          benefit right away. When you call BestVideo, it automatically
  1325.          incorporates the graphics drivers  into  your  compiled  .EXE
  1326.          file.  Usually,  the Borland Graphics Interface files (*.BGI)
  1327.          must be distributed on the disk along with your program.
  1328.             There are several video procedures within the magic  unit.
  1329.          They  are CGAVideo, HercVideo, EGAVideo, VGAVideo, BestVideo,
  1330.          and TextVideo. If you use HercVideo, in place  of  BestVideo,
  1331.          then  the  program  will  work  only on computers equipped to
  1332.          display Hercules Graphics, but the compiled program  will  be
  1333.          much smaller, and you can use absolute coordinates to display
  1334.          graphics.
  1335.             BestVideo  will  link  in  all  the  *.BGI  files and then
  1336.          automatically detect which graphics card is  present  in  any
  1337.          computer, and therefore will run on practically any IBM-clone
  1338.          that  has any graphics card. But BestVideo has to incorporate
  1339.          all the graphics drivers, and therefore the finished  product
  1340.          is  larger.  Furthermore,  when  using BestVideo, you have to
  1341.          account for different resolutions on different machines.   On
  1342.          a CGA machine, the coordinates 0,180 are near the bottom left
  1343.          edge  of  the  screen,  but  on VGA 0,180 is on the left, but
  1344.          nearer to the top of the screen. With BestVideo, you have  to
  1345.          make  calculations  based  on GetMaxX, and GetMaxY, (see your
  1346.          Borland books) or use centered pop-up boxes.
  1347.              TextVideo is the way out of graphics.  For  instance,  if
  1348.          you write a program that starts in graphics mode to display a
  1349.          drawing,  then  you  want  to  switch back to text for faster
  1350.          handling of strings, you simply call the TextVideo procedure.
  1351.              Pop, GetYN, GetAnyKey, Dialog, Menu  and  DoubleMenu  all
  1352.          work almost the same in any graphics mode as in text mode.
  1353.  
  1354.               program prog25;
  1355.               uses crt, video, magic;
  1356.               begin
  1357.                  sent[1] := 'This is text mode';
  1358.                  GetAnyKey(-1,-1);
  1359.                  CGAVideo;
  1360.                  sent[1] := 'This is a graphics mode';
  1361.                  GetAnyKey(-1,-1);
  1362.                  TextVideo;
  1363.                  sent[1] := 'This is text again';
  1364.                  GetAnyKey(-1,-1);
  1365.                  CleanUp;
  1366.               end.
  1367.  
  1368.          Prog25 switches to CGA graphics mode, then back to text mode.
  1369.  
  1370.          Prog26 shows some of the complexity in using BestVideo.
  1371.  
  1372.               program prog26;
  1373.               uses crt, video, graph, magic;
  1374.               begin
  1375.                  sent[1] := 'This is text mode';
  1376.                  GetAnyKey(-1,-1);
  1377.                  BestVideo;
  1378.                  setcolor(yellow);
  1379.                  circle(getmaxx div 2,GetMaxY div 2, GetMaxY div 4);
  1380.                  sent[1] := 'This is a graphics mode';
  1381.                  GetAnyKey(-1,-1);
  1382.                  TextVideo;
  1383.                  CleanUp;
  1384.               end.
  1385.  
  1386.          Notice the new unit.  We are now using a unit that comes with
  1387.          Turbo Pascal called Graph.tpu.  It allows us to make circles,
  1388.          rectangles, lines, change colors, and many other things.  You
  1389.          should  use Graph in all your graphics programs because those
  1390.          which don't make use of it will not be much larger than those
  1391.          that do. Borland's compiler is smart and strips  unused  code
  1392.          out of units as the program is compiled.
  1393.             This one switches to a graphics when a key is pressed.  If
  1394.          you have a VGA system, then you'll see a yellow circle around
  1395.          a  pop-up  box.  But,  then  change  the  "BestVideo" line to
  1396.          "CGAVideo" and you'll  see  that  the  pop-up  box  partially
  1397.          covers  the  circle, even though the circle is supposedly the
  1398.          same size. It's the pop-up that changed.
  1399.             Notice that you can  change  color  by  simply  passing  a
  1400.          color to SetColor.
  1401.  
  1402.          Prog27  shows  a few of the many other things you can do with
  1403.          the Turbo Pascal Graph unit.
  1404.  
  1405.               program prog27;
  1406.               uses crt, video, graph, magic;
  1407.               begin
  1408.                  BestVideo;
  1409.                  SetColor(white);
  1410.                  circle(100,100,50);
  1411.                  circle(100,100,40);
  1412.                  SetFillStyle(solidfill,white);
  1413.                  FloodFill(51,100,white);
  1414.                  SetColor(lightgreen);
  1415.                  SetLineStyle(0,0,3);
  1416.                  rectangle(70,70,130,130);
  1417.                  SetFillStyle(solidfill,lightmagenta);
  1418.                  bar(90,90,110,110);
  1419.                  WaitForUser;
  1420.                  CleanUp;
  1421.               end.
  1422.  
  1423.          Prog28 shows how to work with text in a graphics mode.  Turbo
  1424.          Pascal  supplies  a  default  font,  which  is an 8 x 8 pixel
  1425.          bitmapped font. It is called DefaultFont.
  1426.  
  1427.               program prog28;
  1428.               uses crt, video, graph, magic;
  1429.               begin
  1430.                  BestVideo;
  1431.                  OutTextXY(10,100,'This is the Default font');
  1432.                  WaitForUser;
  1433.                  CleanUp;
  1434.               end.
  1435.  
  1436.          In Prog28 we see that the way to display a string is  through
  1437.          OutTextXY,  which is similar to GoToXY combined with Write in
  1438.          text mode. OutTextXY  requires  screen  coordinates,  then  a
  1439.          string.   Unlike  write  and  writeln,  you  must pass only a
  1440.          string and only one string at a time. You must "str"  numbers
  1441.          before using OutTextXY.
  1442.  
  1443.          Prog29 shows how to work with different fonts.
  1444.  
  1445.               program prog29;
  1446.               uses crt, video, graph, magic;
  1447.               begin
  1448.                  BestVideo;
  1449.                  Triplex;
  1450.                  SetTextStyle(TriplexFont,HorizDir,4);
  1451.                  OutTextXY(0,0,'This is the Triplex font');
  1452.                  WaitForUser;
  1453.                  CleanUp;
  1454.               end.
  1455.  
  1456.          First,  you'll  see  a call to "Triplex." This will cause the
  1457.          external Triplex.Chr file to be compiled  directly  into  the
  1458.          .EXE  file.  You  do not have to distribute finished programs
  1459.          with external *.chr files! But  by  itself,  Triplex  has  no
  1460.          other effect on the program.  If you want to actually use the
  1461.          Triplex  font,  you  have to use "SetTextStyle". SetTextStyle
  1462.          takes three parameters. First is an integer for the  font  to
  1463.          use,  and  these integers also have pre-declared constants in
  1464.          the graph  unit.  Triplex  can  be  referred  to  as  "1"  or
  1465.          TriplexFont.   The   second   number   or   constant  is  the
  1466.          orientation of the text. HorizDir  is  the  most  common,  of
  1467.          course.  It can also be represented with a 0. And finally the
  1468.          size of the font can be controlled with another integer value
  1469.          from 1 to 10.
  1470.             As tempting as it may seem, there are two reasons  not  to
  1471.          use  any fonts except DefaultFont with Pop, GetYN, GetAnyKey,
  1472.          Dialog,  Menu  or Doublemenu.  Gothic, Triplex, SansSerif and
  1473.          Small fonts are drawn rather  than  bitmapped  and  therefore
  1474.          take  longer  to  generate on the screen, slowing the program
  1475.          perceptably.  Furthermore,  because  of  the  way  they   are
  1476.          generated, they don't line up right relative to the general x
  1477.          and y coordinates used by these procedures.
  1478.  
  1479.          If you run prog29 in CGA mode (you can  change  BestVideo  to
  1480.          CGAVideo  to  see)  you'll  notice  that  the  line, "This is
  1481.          Triplex font." is too long to  fit  on  the  screen.  So,  in
  1482.          prog30, lets switch to a different CGA graphics mode.
  1483.  
  1484.               program prog30;
  1485.               uses crt, video, graph, magic;
  1486.               begin
  1487.                  CGAVideo;
  1488.                  SetGraphMode(4);
  1489.                  Triplex;
  1490.                  SettextStyle(TriplexFont,HorizDir,4);
  1491.                  outtextxy(0,0,'This is the Triplex font');
  1492.                  WaitForUser;
  1493.                  CleanUp;
  1494.               end.
  1495.  
  1496.          The line, "SetGraphMode(4)" changes to the higher resolution,
  1497.          2 color, 640 x 200 CGA mode.
  1498.  
  1499.          Prog31  shows  off  some  basic  mouse  work,  and  the  main
  1500.          principal of drawing to the screen.
  1501.  
  1502.               program prog31;
  1503.               uses crt, video, graph, magic;
  1504.               var
  1505.                  x,y : word; {"word" is a positive integer value}
  1506.               begin
  1507.                  BestVideo;
  1508.                  WasteMouse;
  1509.                  repeat
  1510.                     poll(x,y,left,right);
  1511.                     LineTo(x,y);
  1512.                  until left;
  1513.                  CleanUp;
  1514.               end.
  1515.  
  1516.          In prog31 a loop repeats until left becomes true. Left  is  a
  1517.          global  boolean  variable  that  is set to true when the user
  1518.          clicks the left mouse button. Poll is a  function  that  asks
  1519.          the mouse to report it's current status. It tells you through
  1520.          poll, the current screen position, in this case using x and y
  1521.          as word type variables for coordinates, and the status of the
  1522.          left and right mouse buttons. Every time the mouse is polled,
  1523.          a  line is drawn from where the last line ended, to where the
  1524.          mouse is currently.
  1525.              Notice the line, "WasteMouse." This is a procedure  which
  1526.          stalls  the  program until both "left" and "right" are false.
  1527.          (no mouse buttons pressed). Without "WasteMouse" the  program
  1528.          might end immediately.
  1529.  
  1530.          Prog32  shows  you  one  way to move a rectangle around. This
  1531.          program will display the mouse pointer until the  left  mouse
  1532.          button  is  clicked,  then  it  will  turn  it off and show a
  1533.          movable rectangle until the right mouse button is clicked.
  1534.  
  1535.               program prog32;
  1536.               uses crt, video, graph, magic;
  1537.               var
  1538.                  x,y : word;
  1539.               begin
  1540.                  BestVideo;
  1541.                  WasteMouse;
  1542.                  PointerToXY(GetMaxX div 2,GetMaxY div 2);
  1543.                  PointerOn;
  1544.                  repeat Poll(x,y,left,right) until left;
  1545.                  PointerOff;
  1546.                  SetWriteMode(XOrPut);
  1547.                  rectangle(x,y, x + 40, y + 20);
  1548.                  repeat
  1549.                     rectangle(x,y, x + 40, y + 20);
  1550.                     Poll(x,y,left,right);
  1551.                     rectangle(x,y, x + 40, y + 20);
  1552.                  until right;
  1553.                  CleanUp;
  1554.               end.
  1555.  
  1556.          Prog32 shows you how to turn the mouse pointer  on  and  off,
  1557.          and  shows  "SetWriteMode"  so  that you can eliminate images
  1558.          which  have  been  created,  by  merely  writing  them   over
  1559.          themselves.
  1560.  
  1561.          Prog33 shows a couple of small improvements:
  1562.  
  1563.               program prog33;
  1564.               uses crt, video, graph, magic;
  1565.               var
  1566.                  x,y,oldx,oldy : word;
  1567.               begin
  1568.                  BestVideo;
  1569.                  WasteMouse;
  1570.                  SetTextJustify(CenterText,BottomText);
  1571.                  OutTextXY(GetMaxX div 2,GetMaxY - 4,
  1572.                    'Click right mouse button to end program');
  1573.                  SetWriteMode(XOrPut);
  1574.                  rectangle(x,y, x + 40, y + 20);
  1575.                  repeat
  1576.                     repeat
  1577.                        Poll(x,y,left,right);
  1578.                     until (x <> oldx) or (y <> oldy) or right;
  1579.                     rectangle(oldx,oldy, oldx + 40, oldy + 20);
  1580.                     oldx := x;
  1581.                     oldy := y;
  1582.                     rectangle(x,y, x + 40, y + 20);
  1583.                  until right;
  1584.                  CleanUp;
  1585.               end.
  1586.  
  1587.          First,  we  took  off the mouse pointer stuff to simplify the
  1588.          program.  Then we use one of the fancy features of the  Turbo
  1589.          Pascal  Graph  unit to cause text to be centered from left to
  1590.          right around the x coordinate and the bottom  of  the  string
  1591.          will  be  on the y coordinate. And a notice is posted for the
  1592.          user.
  1593.             Then using the new variables, "oldx" and "oldy" within the
  1594.          repeat loop, we check to see if there have been  any  changes
  1595.          in  position  before  moving  the  rectangle. This eliminates
  1596.          annoying flashing.
  1597.  
  1598.          In our last program I'll  show  you  how  to  use  the  sound
  1599.          effects in the magic unit, and we'll fool around with text in
  1600.          graphics modes a bit more.
  1601.  
  1602.               program prog34;
  1603.               uses crt, video, graph, magic;
  1604.               var
  1605.                  x,y,oldx,oldy : word;
  1606.               begin
  1607.                  SoundUp;   (* 1 *)
  1608.                  MainBack := black;    (* 2 *)
  1609.                  BestVideo;
  1610.                  Gothic;     (* 3 *)
  1611.                  Triplex;
  1612.                  SetColor(LightMagenta);
  1613.                  SetTextJustify(CenterText,TopText);   (* 4 *)
  1614.                  SetTextStyle(GothicFont,HorizDir,6);
  1615.                  OutTextXy(GetMaxX div 2,0,'Type Anything');
  1616.                  SetTextStyle(TriplexFont,VertDir,1);
  1617.                  SetTextJustify(LeftText,CenterText);
  1618.                  OutTextXY(20,(GetMaxY div 2) + 30,'Press [Enter]');
  1619.                  OutTextXY(40,(GetMaxY div 2) + 30,'when done.');
  1620.                  SetTextStyle(DefaultFont,HorizDir,2);
  1621.                  SetTextJustify(LeftText,TopText);
  1622.                  SetFillStyle(SolidFill,black);   (* 5 *)
  1623.                  SetColor(LightCyan);
  1624.                  Waste;              (* 6 *)
  1625.                  answer := '';
  1626.                  repeat
  1627.                     u := ReadKey;
  1628.                     pink;    (* 7 *)
  1629.                     if ord(u) > 31 then answer := answer + u;  (* 8 *)
  1630.                     if u = #8 then   (* 9 *)
  1631.                     begin
  1632.                        bar(70,100,70 + TextWidth(answer), (* 10 *)
  1633.                          100 + TextHeight(answer));
  1634.                        delete(answer,length(answer),1);  (* 11 *)
  1635.                     end;
  1636.                     OutTextXY(70,100,answer);
  1637.                  until u = #13;
  1638.                  SoundDown;
  1639.                  delay(500);  (* 12 *)
  1640.                  Twinkle;
  1641.                  CleanUp;
  1642.               end.
  1643.  
  1644.          Prog34 has notes within (* and *):
  1645.  
  1646.          Note  1)  One  of the four sound effects built into the magic
  1647.          unit. To use one of the effects, simply call it's  procedure.
  1648.          Sometimes  sounds  don't  behave  as  expected  with machines
  1649.          faster  than  33mhz  or  when  heavily  multitasked  (running
  1650.          concurrently   with   other  programs)  under  MS-Windows  or
  1651.          Deskview.
  1652.  
  1653.          Note 2) By setting the main background color to black  before
  1654.          a call to BestVideo, the video mode will start and run with a
  1655.          black background.
  1656.  
  1657.          Note  3) These procedures, Gothic and Triplex hook in the two
  1658.          fonts besides the default font that this program is going  to
  1659.          use. There will be no need for *.chr files on the disk with a
  1660.          compiled program.
  1661.  
  1662.          Note 4) SetTextJustify will center a title on the screen when
  1663.          set this way.
  1664.  
  1665.          Note  5)  SetFillStyle  is  used  to establish parameters for
  1666.          "bar," used a few lines down in this program.  Bar will  make
  1667.          a solid rectangle in the color specified (black in this case)
  1668.          This is a good way to erase text in graphics modes.
  1669.  
  1670.          Note  6)  Waste stalls the program until no mouse buttons are
  1671.          pressed  and  no  characters  have  been  entered  from   the
  1672.          keyboard.   If  a  key  had  been pressed as this program was
  1673.          starting, it would be reflected as the first character  in  a
  1674.          string the user is going to type.
  1675.  
  1676.          Note  7) "Pink" is a sound effect, typically used to indicate
  1677.          a small action has occurred, such as a key has been pressed.
  1678.  
  1679.          Note 8) "Ord" returns the ordinal position in a  set  of  the
  1680.          variable  specified  in  parentheses.   When  used with ASCII
  1681.          characters, Ord returns their ASCII number.  What  this  line
  1682.          does  is  eliminates  adding  characters to the string called
  1683.          "answer" if they might be unprintable characters.
  1684.  
  1685.          Note 9) u is  ASCII  #8  when  the  backspace  key  has  been
  1686.          pressed.
  1687.  
  1688.          Note  10)  "Bar"  is  being  used  to erase "answer" from the
  1689.          screen  because  the  backspace  key  has  been  pressed  and
  1690.          therefore  the  user wants to eliminate the last character in
  1691.          answer.  The Bar will  erase  it,  and  a  newer  version  of
  1692.          answer,  one  which  will  be  one  character shorter will be
  1693.          written in its place. TextWidth and TextHeight are  excellent
  1694.          functions  provided  by  Turbo  Pascal  to determine how many
  1695.          pixels wide and how many pixels high a string are, no  matter
  1696.          what font and size are selected.
  1697.  
  1698.          Note 11) "Delete" is a  way  to  shorten  a  string.   Delete
  1699.          requires  three  parameters,  the string on which to operate,
  1700.          the character position in the string at which to delete,  and
  1701.          the number of characters to take out. There are several other
  1702.          string  procedures  available from Turbo Pascal including Pos
  1703.          (find the position of a matching sub-string within a string),
  1704.          Copy (make a sub-string from a string), and ConCat  (add  two
  1705.          strings  together). See your Borland Turbo Pascal manuals for
  1706.          more information about string handling.
  1707.  
  1708.          Note  12)  Delay  is  called between two sound effects to put
  1709.          some time between them. Delay requires one number, an integer
  1710.          representing the number of milliseconds to delay.  There  are
  1711.          1000 milliseconds in one second, so this delay is 1/2 second.
  1712.          While Delay is running, no other actions can take place.
  1713.  
  1714.                                      - - -
  1715.  
  1716.             And  that almost wraps up this tutorial! Hope you have had
  1717.          as much fun reading and experimenting as I did writing it.
  1718.             There  is  far  more  available  in Turbo Pascal than this
  1719.          short tutorial can tell you about.  To learn as much  as  you
  1720.          can,  in  a  reasonable  amount  of time, I recommend getting
  1721.          several books on Turbo Pascal, and experimenting  with  every
  1722.          idea that crosses your mind.
  1723.             In  fact,  there's  quite  a  bit  more  to the Magic unit
  1724.          itself.   You  can  read   Magic.Doc   to  learn  more of its
  1725.          included procedures and functions,  and  get  more  technical
  1726.          information on the ones you already know.
  1727.             This is shareware. Feel free to copy and distribute Pascal
  1728.          Magic as long as all files remain intact and unchanged.
  1729.             If  you  have  paid a professional shareware distributor a
  1730.          few dollars for this disk, you have paid for the  service  of
  1731.          providing a copy.
  1732.             If  you  use  MAGIC.TPU  in  your programs, or if you have
  1733.          found this tutorial helpful, you must pay for the creation of
  1734.          the product. Send $29.95 to:
  1735.  
  1736.                                 Another Company
  1737.                                  P.O. Box 298
  1738.                               Applegate, OR 97530
  1739.  
  1740.             Complete source code is available for the MAGIC.TPU.  This
  1741.          is good for using as a framework for your own very customized
  1742.          applications,   for   learning   more   about   Turbo  Pascal
  1743.          Programming, for  stripping  down  top  efficiency,  and  for
  1744.          improving,  since  you  will  probably  soon become (or might
  1745.          already be) a better programmer than I am.  For  registration
  1746.          AND source code, send $59.90 and please specify disk size.
  1747.  
  1748.          This is version 1.0 and you may find a bug or two.  I make no
  1749.          guarantees about it's suitability to your programming needs.
  1750.  
  1751.          If  we  find  any major bugs, they will probably be corrected
  1752.          by the time you get your registered version!
  1753.  
  1754.          If  you require technical assistance, you can try to phone me
  1755.          at 503-846-7884. Best bet is 9-5 weekdays, but I'm not always
  1756.          available.
  1757.  
  1758.          Since you are going to write  some  wonderful  programs,  you
  1759.          might as well start making money with them! You won't have to
  1760.          work  in  an  office doing programming for someone else.  You
  1761.          can write exactly the kind of programs you want to write, and
  1762.          make money at home!
  1763.              The  'secret'  is shareware.  Does it work?  You bet! You
  1764.          can easily have a small success, making some  extra  spending
  1765.          money  each month, or with some practice, you can have a wild
  1766.          success, and make a fine living! There are some  millionaires
  1767.          who   make   their   ever-growing  fortune  entirely  through
  1768.          shareware.
  1769.              ANOTHER  COMPANY  shows  you everything.  Besides our own
  1770.          shareware  successes,  including  WRITER'S   DREAM,   BICYCLE
  1771.          TUNE-UP  AND  REPAIR,  MONEY,  BLACKBOARD,  BETTER  EYESIGHT,
  1772.          WHAT'S  IN  THAT  BOX?  and  THE UNIVERSAL CONVERTER, we have
  1773.          researched the shareware market, we  have  interviewed  other
  1774.          shareware  authors  and  have  learned about all sides of the
  1775.          rapidly expanding shareware business.
  1776.               We show you how  to  write  programs  that  capture  the
  1777.          public's   interest,   how   to   make  sure  your  customers
  1778.          'register', and how to get money by other means through  your
  1779.          shareware.  We  show  you  more. We show you frequency charts
  1780.          indicating which  types  of  programs  sell  best,  we  offer
  1781.          suggestions  for  programs as yet unwritten,  we  talk  about
  1782.          your  on-disk  instruction  manuals,  we even show you how to
  1783.          write user-friendliness into your programs.
  1784.               Can  you  succeed without  SUCCESS WITH SHAREWARE?  Yes!
  1785.          But  why do  it  the  hard  way?  We  have  learned  all  the
  1786.          super-professional   approaches,   the   pitfalls   and   the
  1787.          shortcuts. We'll tell you all about it, and then  instead  of
  1788.          stumbling  around  for  the  first couple of years, you'll be
  1789.          a professional from the start!
  1790.              To get your copy of SUCCESS WITH SHAREWARE! (which is not
  1791.          shareware, itself - only  available  from  Another  Company),
  1792.          send $19.95. Please specify if you need 3.5" disk size.
  1793.  
  1794.                                                          Thanks,
  1795.                                                      - Jeff Napier -
  1796.                                                      January 9, 1992
  1797.  
  1798.          You can order products by writing your order on plain  paper,
  1799.          or  by  printing the included ASCII file called Order.frm, or
  1800.          by phoning 1-503-846-7884, generally weekdays between  9  and
  1801.          5, west coast time.
  1802.