home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / basic / pbvl010.zip / TUTORIAL.DOC < prev    next >
Text File  |  1994-02-10  |  93KB  |  1,994 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.           ┌───────────────────────────────────────────────────────┐
  7.           │                                                       │
  8.           │            P B / V I S I O N (tm)   L I T E           │
  9.           │      Visual Windowing Library for PowerBASIC 3.0      │
  10.           │  >>>>>>>>>>  SHAREWARE EVALUATION VERSION <<<<<<<<<<  │
  11.           │                                                       │
  12.           │                       TUTORIAL                        │
  13.           │                                                       │
  14.           │    (c) Copyright 1993-94 DSE Software Publishing      │
  15.           │       Licensed Material.  All Rights Reserved.        │
  16.           │                                                       │
  17.           │        ┌────────────────────────────────────┐         │
  18.           │        │ ▀▀▀▀▀▀▀▀\      ▀▀▀▀▀▀\ ▀▀▀▀▀▀▀▀▀▀\ │         │
  19.           │        │  ▀▀▀\   ▀\    ▀▀\   ▀▀\ ▀▀▀\   ▀▀\ │         │
  20.           │        │  ▀▀▀\    ▀\  ▀▀\     ▀\ ▀▀▀\    ▀\ │         │
  21.           │        │  ▀▀▀\    ▀▀\ ▀▀\        ▀▀▀\       │         │
  22.           │        │  ▀▀▀\    ▀▀\ ▀▀▀\       ▀▀▀\ ▀\    │         │
  23.           │        │  ▀▀▀\    ▀▀\  ▀▀▀\      ▀▀▀\ ▀\    │         │
  24.           │        │  ▀▀▀\    ▀▀\    ▀▀▀\    ▀▀▀▀▀▀\    │         │
  25.           │        │  ▀▀▀\    ▀▀\      ▀▀▀\  ▀▀▀\ ▀\    │         │
  26.           │        │  ▀▀▀\    ▀▀\       ▀▀▀\ ▀▀▀\ ▀\    │         │
  27.           │        │  ▀▀▀\    ▀▀\        ▀▀\ ▀▀▀\       │         │
  28.           │        │  ▀▀▀\    ▀\  ▀\     ▀▀\ ▀▀▀\    ▀\ │         │
  29.           │        │  ▀▀▀\   ▀\   ▀▀\   ▀▀\  ▀▀▀\   ▀▀\ │         │
  30.           │        │ ▀▀▀▀▀▀▀▀\     ▀▀▀▀▀▀\  ▀▀▀▀▀▀▀▀▀▀\ │         │
  31.           │        └────────────────────────────────────┘         │
  32.           │                                                       │
  33.           │                DSE Software Publishing                │
  34.           │                  Post Office Box 96                   │
  35.           │                Willits, CA 95490-0096                 │
  36.           │                    (707) 459-4358                     │
  37.           │                 FAX: (707) 459-4484                   │
  38.           │                                                       │
  39.           │        InterNet: dse.software@genie.geis.com          │
  40.           │           DSE Online! BBS - (707) 459-4484            │
  41.           │                 GEnie: DSE.SOFTWARE                   │
  42.           │                                                       │
  43.           └───────────────────────────────────────────────────────┘
  44.  
  45.           PowerBASIC is a registered trademark of PowerBASIC, Inc.
  46.           PB/VISION(tm) and PB/WORKSHOP(tm) are trademarks of DSE
  47.           Software Publishing.  Other product names are trademarks
  48.           or registered trademarks of their respective holders.
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.                                     Contents
  60.  
  61.  
  62.  
  63.                Chapter 1  WINDOWING BASICS                           2
  64.                   In the Beginning...  . . . . . . . . . . . . . . . 2
  65.                   Important Reading  . . . . . . . . . . . . . . . . 2
  66.                   Tutor Source Code Organization . . . . . . . . . . 2
  67.                   1.1  Let's get started with TUTOR1_1.BAS . . . . . 3
  68.                      1.1.1  What is "%ISPBU" for anyway? . . . . . . 3
  69.                      1.1.2  Trivial, but worth mentioning. . . . . . 3
  70.                      1.1.3  The "WINDOW.BI" $INCLUDE File. . . . . . 4
  71.                      1.1.4  Initializing the program with
  72.                             "AppInit()"  . . . . . . . . . . . . . . 4
  73.                      1.1.5  Shutting the Program down with
  74.                             "AppClose()" . . . . . . . . . . . . . . 4
  75.                   1.2  Moving on up to TUTOR1_2.BAS  . . . . . . . . 4
  76.                      1.2.1  What is all this "Virtual Handle" Mumbo-
  77.                             Jumbo? . . . . . . . . . . . . . . . . . 5
  78.                      1.2.2  How come WinOpen() looks so darn
  79.                             complex? . . . . . . . . . . . . . . . . 5
  80.                      1.2.3  "Colors, Colors Everywhere" or "Ooh Yuck,
  81.                             Hexadecimal" . . . . . . . . . . . . . . 6
  82.                      1.2.4  What are "Extended Colors"?  . . . . . . 7
  83.                      1.2.5  And now, back to WinOpen() . . . . . . . 8
  84.                      1.2.6  Flag Waving Windows  . . . . . . . . . . 9
  85.                      1.2.7  Displaying a Window  . . . . . . . . .  10
  86.                      1.2.8  Another way of Opening a Window  . . .  11
  87.                      1.2.9  Printing to a Window . . . . . . . . .  11
  88.                      1.2.10  Closing an open Window  . . . . . . .  12
  89.                   1.3  Customizing the "Desktop" . . . . . . . . .  13
  90.                      1.3.1  Text or Graphics . . . . . . . . . . .  13
  91.                      1.3.2  Changing the Desktop Color and Fill
  92.                             Pattern  . . . . . . . . . . . . . . .  14
  93.                      1.3.3  Adding a "Title Bar" . . . . . . . . .  14
  94.  
  95.                Chapter 2  EVENT MANAGEMENT                          15
  96.                   Input, Need Input! . . . . . . . . . . . . . . .  15
  97.                   2.1  Your First "Event-Driven" Program . . . . .  16
  98.                      2.1.1  The "EVENT.BI" $INCLUDE File . . . . .  16
  99.                      2.1.2  Polling "GetEvent()" for Events  . . .  17
  100.                   2.2  Responding to the Keyboard  . . . . . . . .  17
  101.                      2.2.1  Responding to Alpha-Numeric keys with
  102.                             "KEYGET" . . . . . . . . . . . . . . .  18
  103.                      2.2.2  Responding to built-in Keyboard
  104.                             Events . . . . . . . . . . . . . . . .  18
  105.                      2.2.3  Getting Help with <F1> . . . . . . . .  18
  106.  
  107.                                           i
  108.  
  109.  
  110.  
  111.                   2.3  How to create "Custom" Keyboard Event
  112.                        Codes . . . . . . . . . . . . . . . . . . .  18
  113.                      2.3.1  Defining a few Custom Event Codes  . .  19
  114.                      2.3.2  Adding the Custom Events . . . . . . .  20
  115.                      2.3.3  Responding to Custom Events  . . . . .  20
  116.                   2.4  Of Mice and Windows . . . . . . . . . . . .  20
  117.                      2.4.1  Selecting the Mouse Cursor Style . . .  21
  118.                      2.4.2  Making your program "Mouse Aware"  . .  21
  119.                      2.4.3  Making Windows Mouse Aware . . . . . .  22
  120.                      2.4.4  Responding to "Mouse Events" . . . . .  22
  121.  
  122.                Chapter 3  ADVANCED PROGRAMMING TECHNIQUES           23
  123.                   3.1  Multi-Threading made easy.  . . . . . . . .  23
  124.                      3.1.1  Assigning Code to a Window.  . . . . .  24
  125.                      3.1.2  Syntax of a Window Subroutine. . . . .  25
  126.                      3.1.3  Processing Events in a Window
  127.                             Subroutine.  . . . . . . . . . . . . .  26
  128.                      3.1.4  Returning Event Codes back to
  129.                             GETEVENT().  . . . . . . . . . . . . .  26
  130.                   3.2  Multi-Threading Continued - A Couple of New
  131.                        Events. . . . . . . . . . . . . . . . . . .  26
  132.                      3.2.1  Some New Events Codes. . . . . . . . .  27
  133.                   3.3  Complex Multi-Threaded Program. . . . . . .  27
  134.                      3.3.1  Making the Code More Readable. . . . .  27
  135.                      3.3.2  Initializing the Selection Window. . .  27
  136.                      3.3.3  Responding to Window Clicks  . . . . .  28
  137.                      3.3.4  Returning a Modified Event Code  . . .  28
  138.                   3.4  Child Menus and Forms without Overkill. . .  28
  139.                   3.5  Background Tasking  . . . . . . . . . . . .  29
  140.                   3.6  Making programs smaller with "Stub" Files. . 30
  141.                      3.6.1  The "NOGRAPH.OBJ" and "NOTEXT.OBJ" Stub
  142.                             Files. . . . . . . . . . . . . . . . .  30
  143.                      3.6.2  The "NOMOUSE.OBJ" Stub File  . . . . .  31
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.                                          ii
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.                                     Figures
  176.  
  177.  
  178.                Figure 2.1: A little "black box" called GETEVENT()  .16
  179.                Figure 3.1: Simplified GETEVENT() flowchart.  . . . .23
  180.                Figure 3.2: GETEVENT() with "Multi-Threading".  . . .24
  181.                Figure 3.3: "Multi-Threading" multiple objects. . . .24
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.                                          iii
  224.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  225.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  226.  
  227.                                       Chapter 1
  228.  
  229.                                   WINDOWING BASICS
  230.  
  231.           █████████████████████████████████████████████████████████████████
  232.  
  233.           In the Beginning...
  234.           ─────────────────────────────────────────────────────────────────
  235.  
  236.                Welcome to the PB/VISION(tm) tutorial.  The purpose of this
  237.                tutorial is to gently (and humorously) guide you through the
  238.                learning phase of PB/VISION.  Step by step, I'll take you
  239.                from the simplest possible "Hello, World!" program to
  240.                elaborate event-driven object-oriented programs that will
  241.                make your friends green with envy.
  242.  
  243.           Important Reading
  244.           ─────────────────────────────────────────────────────────────────
  245.  
  246.                Before diving into it, please let me give you a word of
  247.                advice:  READ THIS ENTIRE TUTORIAL _BEFORE_ ATTEMPTING TO
  248.                WRITE YOUR OWN PROGRAMS!  Sorry, I didn't mean to shout but
  249.                we get a lot calls from people asking "What tutorial?", or
  250.                saying "I just skimmed over them".
  251.  
  252.                In all seriousness, even if you do not plan on using all of
  253.                the library features, do not skip or quickly skim over those
  254.                parts.  This tutorial is designed to build on knowledge
  255.                learned from previous chapters.  No chapter is self-
  256.                contained.  If you miss even one, you are going to become
  257.                overwhelmed and frustrated, and you will have wasted good
  258.                money.
  259.  
  260.                While you experienced programmers may be able to pick up on
  261.                things by studying and taking a hatchet to the demos, you
  262.                will also miss out on things that will make you say "Dang!"
  263.                later on.  Please, humor me, keep reading.
  264.  
  265.           Tutor Source Code Organization
  266.           ─────────────────────────────────────────────────────────────────
  267.  
  268.                Each section of this tutorial is accompanied by one or more
  269.                TUTOR??.BAS files.  For maximum readability, only the newest
  270.                concepts are commented in the source files.  You will not
  271.                see old comments in a new source file unless it is
  272.                absolutely necessary.
  273.  
  274.                So that you can keep track of which part of the tutorial
  275.                correlates with the source file, each section of the source
  276.                is commented with the chapter and section.  I don't think
  277.                you will get lost.
  278.  
  279.  
  280.  
  281.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  282.           (c) Copyright 1993-1994 DSE Software Publishing                2
  283.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  284.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  285.  
  286.           1.1  Let's get started with TUTOR1_1.BAS
  287.           ─────────────────────────────────────────────────────────────────
  288.  
  289.                Start up PowerBASIC and load the file named "TUTOR1_1.BAS".
  290.                This is as simple as it gets.  I know you're curious, so go
  291.                ahead and run it.  If all goes well, you should see "Hello,
  292.                World" plastered on a blue matte background.  If not, read
  293.                the "TROUBLESHOOTING" section in the documentation.  Ok,
  294.                press a key (any key) to get back to the source code.
  295.  
  296.                By the way, all of the files were created with a tab size of
  297.                8.  If you have any other value, the comments are going to
  298.                look _real_ funny.  You can set the tab size under the
  299.                "Options|Environment|Tab Size" menu on the PowerBASIC
  300.                editor.
  301.  
  302.                Ok, lets analyze this one line by line...
  303.  
  304.  
  305.           1.1.1  What is "%ISPBU" for anyway?
  306.           ─────────────────────────────────────────────────────────────────
  307.  
  308.                The first statement reads "%ISPBU = 0".  This  little
  309.                constant (meaning a fixed variable) determines how the file
  310.                is going to be used.  You see, all of the $INCLUDE files are
  311.                designed so that they may be used for creating executable
  312.                files (.EXE) or "units" (.PBU).  If you are compiling a
  313.                normal program, you will use a value of 0 (zero).  If you
  314.                are compiling a "unit", use a value of 1 (one).
  315.  
  316.                Depending on the way "%ISPBU%" is set, you are telling
  317.                PowerBASIC to compile some parts of the file, but not
  318.                others.  This is accomplished through a method called
  319.                "conditional compiling".  If you want to get a little more
  320.                familiar with the term, drag out the PowerBASIC manuals and
  321.                look up references for "$IF/$ELSE/$ENDIF".
  322.  
  323.  
  324.           1.1.2  Trivial, but worth mentioning.
  325.           ─────────────────────────────────────────────────────────────────
  326.  
  327.                The next two statements (lines 9 and 10) don't look very
  328.                important, but they are.  "DEFINT A-Z" tells PowerBASIC to
  329.                default to integer math, meaning that all variables are
  330.                assumed to be integers (unless otherwise stated so).
  331.                Without it, PowerBASIC will use slower "floating point" math
  332.                for all calculations.  Depending on the CPU, integer math is
  333.                up to 20 times faster than floating point.
  334.  
  335.                The "$DYNAMIC" statement, tells PowerBASIC to allocate
  336.                memory only as needed.  Without it, all memory is allocated
  337.                as soon as the program starts and you might find yourself
  338.                short on it later.
  339.  
  340.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  341.           (c) Copyright 1993-1994 DSE Software Publishing                3
  342.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  343.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  344.  
  345.                Simply put, these two lines guarantee that PB/VISION (and
  346.                PowerBASIC) will work as fast and efficiently as possible.
  347.                You should have these lines in every program you write, even
  348.                if you aren't using any PB/VISION routines.
  349.  
  350.  
  351.           1.1.3  The "WINDOW.BI" $INCLUDE File.
  352.           ─────────────────────────────────────────────────────────────────
  353.  
  354.                On line 14 we specify the "WINDOW.BI" $INCLUDE file.  This
  355.                file has the definitions for all of the PB/VISION windowing
  356.                routines, and the commands to properly link in the PB/VISION
  357.                library.  Without this line, you will not be able to use any
  358.                PB/VISION routines.
  359.  
  360.                PB/VISION is supplied with other $INCLUDE files for menu,
  361.                data entry, and other miscellaneous routines.  We will get
  362.                to these in a while.
  363.  
  364.  
  365.           1.1.4  Initializing the program with "AppInit()"
  366.           ─────────────────────────────────────────────────────────────────
  367.  
  368.                APPINIT() is the routine that turns on PB/VISION.  When
  369.                called, it determines what type of equipment you have and
  370.                adjusts the library routines accordingly.  By default, it
  371.                paints the screen with a white on blue matte background.
  372.                This is called the "desktop".  In a few pages, I'll tell you
  373.                how to customize the look and feel of the desktop.  For now,
  374.                we will use the default.
  375.  
  376.                The next couple of lines are pure PowerBASIC code to print
  377.                "Hello, World!" and wait for the user to press a key.  Press
  378.                any key and read on.
  379.  
  380.  
  381.           1.1.5  Shutting the Program down with "AppClose()"
  382.           ─────────────────────────────────────────────────────────────────
  383.  
  384.                APPCLOSE() is the opposite of APPINIT().  When called, it
  385.                closes all open windows, clears off the desktop, and
  386.                restores the screen to the exact same state it was in when
  387.                the program started.
  388.  
  389.                That's it for TUTOR1_1.BAS.
  390.  
  391.  
  392.           1.2  Moving on up to TUTOR1_2.BAS
  393.           ─────────────────────────────────────────────────────────────────
  394.  
  395.                Now load and run the file named "TUTOR1_2.BAS".  In this
  396.                demo  we open up a window and print some text in it.  When
  397.                you're ready, press a key to end the demo.
  398.  
  399.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  400.           (c) Copyright 1993-1994 DSE Software Publishing                4
  401.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  402.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  403.  
  404.           1.2.1  What is all this "Virtual Handle" Mumbo-Jumbo?
  405.           ─────────────────────────────────────────────────────────────────
  406.  
  407.                Introduced in this section is the WINOPEN() routine, whose
  408.                job is to create what is known as a "handle based virtual
  409.                window".  That's a mighty big concept, but in all actuality,
  410.                it is very easy to understand.
  411.  
  412.                The "handle" part is the simplest concept to grasp.  Think
  413.                of it as your Aunt Edna's telephone number.  When you want
  414.                to talk to her, you dial her number.  A window handle is the
  415.                same thing.  In order to "talk" to a window, you have to
  416.                know its "phone number".  Whenever you "open" (create) a new
  417.                window, it lets you know what its handle is.  In this
  418.                particular example, WINOPEN() assigns the window's handle to
  419.                a variable called "AuntEdna%".
  420.  
  421.                As for the "virtual" part, well, my dictionary defines this
  422.                as "virtuous", but somehow I don't think that this term
  423.                applies here.  In windowing terminology, "virtual" means
  424.                that there is more to the window than the eye can see.
  425.                As an example, imagine a piece of paper with a hole in the
  426.                middle.  Now place that piece of paper over a page in an
  427.                open book.  All you can see is the text through the hole,
  428.                but if you move the book underneath you will be able to see
  429.                the rest of the text.  This is called "virtualization", and
  430.                yes, it is legal in most states.
  431.  
  432.                With a "virtual" window, all you see is the text coming
  433.                through the hole.  In the library, there are functions that
  434.                exist solely to move the "book" around.  There are also
  435.                functions for printing to a window, scroll text within a
  436.                window, clearing text from a window, and all kinds of simple
  437.                and fancy window things.
  438.  
  439.  
  440.           1.2.2  How come WinOpen() looks so darn complex?
  441.           ─────────────────────────────────────────────────────────────────
  442.  
  443.                At your first glance, all those parameters being passed to
  444.                WINOPEN() might scare you off.  Don't let it, as it is
  445.                considerably easier than it looks.  Additionally, if you get
  446.                stuck, you can always bring up the help screen for this
  447.                routine by pressing <CTRL-F1> when the cursor is on function
  448.                or procedure name.
  449.  
  450.                Let's take this routine apart.
  451.  
  452.                     AuntEdna = WINOPEN(10, 40, &H10, 1, &H1F, "AUNT EDNA'S
  453.                                         WINDOW ", &HE0, %SHADOW)
  454.  
  455.                     1. Virtual Rows..: 10
  456.                     2. Virtual Cols..: 40
  457.  
  458.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  459.           (c) Copyright 1993-1994 DSE Software Publishing                5
  460.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  461.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  462.  
  463.                     3. Attribute.....: &H10   ; black on blue
  464.                     4. Border........: 1
  465.                     5. Border Color..: &H1F   ; bright white on blue
  466.                     6. Title.........: "AUNT EDNA'S WINDOW"
  467.                     7. Title Color...: &HE0   ; black on yellow
  468.                     8. Window flags..: %SHADOW
  469.  
  470.                The first two parameters specify the "VIRTUAL ROWS" and
  471.                "VIRTUAL COLUMNS".  In this instance we define a window of
  472.                10 rows by 40 columns.  There is nothing stopping you from
  473.                using larger or smaller numbers.  You could in fact define a
  474.                window that is 80 rows by 132 columns if the desire hits
  475.                you.
  476.  
  477.  
  478.           1.2.3  "Colors, Colors Everywhere" or "Ooh Yuck, Hexadecimal"
  479.           ─────────────────────────────────────────────────────────────────
  480.  
  481.                Next comes the "ATTRIBUTE" parameter, whichis a hexadecimal
  482.                code that defines the  window color.  Ole Aunt Edna is
  483.                scared of hexadecimal math because she thinks it's witches'
  484.                math.  You know better.  In fact, it is so simple that it is
  485.                only going to take you 30 seconds to learn how to use them
  486.                if you don't know how yet.
  487.  
  488.                To get you in the right frame of mind, lets start with
  489.                PowerBASIC's built-in "COLOR" statement.  You have used this
  490.                statement thousands of times.  It defines the color for the
  491.                next "PRINT" statement.  COLOR accepts two parameters:
  492.  
  493.                     COLOR foreground%, background%
  494.  
  495.                Lets take this apart:
  496.  
  497.                     COLOR 7, 0          ' white on black text
  498.                     COLOR 1, 7          ' blue on white text
  499.  
  500.                The first digit defines the foreground color, and the second
  501.                digit defines the background color.  Are you with me so far?
  502.  
  503.                Using hexadecimal, you would simply switch the two numbers
  504.                and prefix them with "&H":
  505.  
  506.                     &H background foreground
  507.  
  508.                or:
  509.  
  510.                     &H07                ' white on black text
  511.                     &H71                ' blue on white text
  512.  
  513.                All we have done is reverse the two numbers and add a couple
  514.                of funny letters.  There is nothing more to it.  You may
  515.  
  516.  
  517.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  518.           (c) Copyright 1993-1994 DSE Software Publishing                6
  519.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  520.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  521.  
  522.                already know the numbers for most of the colors, but here
  523.                are the numbers for all of them.
  524.  
  525.                     0 = black           8 = Gray (bright black!)
  526.                     1 = blue            9 = bright blue
  527.                     2 = green           A = bright green (10)
  528.                     3 = cyan            B = bright cyan (11)
  529.                     4 = red             C = bright red (12)
  530.                     5 = magenta         D = bright magenta (13)
  531.                     6 = brown           E = yellow (14)
  532.                     7 = white           F = bright white (15)
  533.  
  534.                Okay, okay.  Not all of them are numbers.  I sneaked (or is
  535.                that "snuck"?) a few letters in there too, but they work the
  536.                same way:
  537.  
  538.                     &H1F                ' bright white on blue text
  539.                     &HEC                ' bright red on yellow
  540.  
  541.                A word of warning on the last one (&HEC)...  Wear very dark
  542.                sunglasses if you make a window this color.
  543.  
  544.                If you forget which number corresponds to a given color,
  545.                help is a keystroke away.  You can bring up the PB/VISION
  546.                online help by pressing <F1> and then <SHIFT-F1> while in
  547.                the editor.
  548.  
  549.                For the faint of heart, there is a function called ATTR(),
  550.                and it works identically to PowerBASIC's own "COLOR"
  551.                statement.  It does, however, add a minimum of 25 bytes of
  552.                code each and every time you use it.  Most times it will add
  553.                even more.
  554.  
  555.  
  556.           1.2.4  What are "Extended Colors"?
  557.           ─────────────────────────────────────────────────────────────────
  558.  
  559.                Just when you thought you knew everything about colors, I am
  560.                here to confuse you (not really) again.
  561.  
  562.                I shouldn't be telling you this right now, but I have a
  563.                sneaky suspicion that you have been looking ahead at the
  564.                other demo programs.  If so, you might be getting confused
  565.                over the "extended" color codes used when calling particular
  566.                routines.
  567.  
  568.                Some routines, such as WINHOTPRINT(), allow different parts
  569.                of a text string to be printed in different colors.  Lets
  570.                use the following as an example, which is a variation of the
  571.                WINPRINT() routine:
  572.  
  573.                     WINHOTPRINT AuntEdna, 1, 1, &H0F07, "Hello, ~W~orld!"
  574.  
  575.  
  576.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  577.           (c) Copyright 1993-1994 DSE Software Publishing                7
  578.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  579.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  580.  
  581.                This statement prints "Hello, World!" to a window.  What is
  582.                special is that the "W" in "World" is printed in a color
  583.                different from the rest of the text.  How is this done?  I'm
  584.                glad you ask, read on...
  585.  
  586.                In routines that allow extended color codes, all text
  587.                outside the tilde (~) characters will be printed with the
  588.                primary color, and all text braced between two tilde
  589.                characters will be printed with the secondary color.
  590.  
  591.                Extended color codes are created by combining two color
  592.                codes.  The default color is placed on the right side of the
  593.                code, and the secondary color is placed on the left.  It's
  594.                that easy!
  595.  
  596.                     WINHOTPRINT AuntEdna, 1, 1, &H0F07, "Hello, ~W~orld!"
  597.                                                   ││││
  598.                               Secondary color ────┴┘└┴──── Primary color
  599.                                                &H0F  &H07
  600.  
  601.                If you don't supply the secondary code, the primary will be
  602.                used by default.
  603.  
  604.  
  605.           1.2.5  And now, back to WinOpen()
  606.           ─────────────────────────────────────────────────────────────────
  607.  
  608.                Let's get back to WINOPEN().
  609.  
  610.                AuntEdna = WINOPEN(10, 40, &H10, 1, &H1F, "", &HE0, %SHADOW)
  611.  
  612.                The "BORDER" parameter (1) defines what border style is used
  613.                when the window is displayed.  While in standard text mode,
  614.                there are 17 border styles available.  When the graphical
  615.                mode is enabled, there is only 1 border style.
  616.  
  617.                For the "BORDER COLOR", at time you may want the color of
  618.                the border to differ slightly (or greatly) from the text
  619.                color, so modify this to your hearts content.
  620.  
  621.                The "TITLE" and "TITLE COLOR" work the same way.  You may
  622.                use up to 40 characters in a title.  Anything beyond that
  623.                point is chopped off.
  624.  
  625.                Finally there is the window "WINDOW FLAGS" parameter.  This
  626.                deserves a section of its own.
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  636.           (c) Copyright 1993-1994 DSE Software Publishing                8
  637.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  638.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  639.  
  640.           1.2.6  Flag Waving Windows
  641.           ─────────────────────────────────────────────────────────────────
  642.  
  643.                The "WINDOW FLAGS" parameter defines the look, feel, and
  644.                response of a window.  It allows you to add a shadow, scroll
  645.                bars, icons, and more.
  646.  
  647.                To make things easier for you, all of the window flags have
  648.                been defined using constants (variables that don't change).
  649.                All you will have to remember are names, and not numbers.
  650.                And once again, if you forget any of the names, you can
  651.                always pull them up through the online help system.
  652.  
  653.                In this example, only "%SHADOW" is used.   This particular
  654.                option places a shadow at the lower right corner of the
  655.                window.  There are quite a few options available, and here
  656.                is a list of the rest:
  657.  
  658.                     Constant       Description
  659.                     ─────────────  ────────────────────────────────────────
  660.                     %AUTOCLOSE     Forces window to close if it becomes
  661.                                    hidden.
  662.                     %AUTOSCROLL    Coordinates window scroll relative to
  663.                                    window viewport and allows mouse and
  664.                                    keyboard scrolling of window.
  665.                     %BOTTOMBAR     Adds an attractive bottom bar to
  666.                                    graphical windows that do not already
  667.                                    have one.
  668.                     %CONTROL       Add a control box icon to the window
  669.                                    (See WINCTRLBOX().
  670.                     %DRAGBAR       Add a drag bar to the window.
  671.                     %HSCROLLBAR    Add a horizontal scroll bar to the
  672.                                    window.
  673.                     %MINMAX        Add minimize and maximize icons to the
  674.                                    window.
  675.                     %NOHORZBORDER  Remove horizontal border from window.
  676.                     %NOCOLOR       Defines that all text in the window is
  677.                                    of one color (saves 50% memory).
  678.                     %NOHIDE        Does not allow window to be hidden.
  679.                     %NOSELECT      Disables all mouse manipulation of a
  680.                                    window.
  681.                     %NOVERTBORDER  Remove vertical border from window.
  682.                     %RESIZE        Add a resize icon to the window.
  683.                     %SHADOW        Add a shadow to the window (lower/right)
  684.                     %VSCROLLBAR    Add a vertical scroll bar to the window.
  685.  
  686.                You can use a single flag or you can merge several together.
  687.                Don't worry if you don't understand what all the different
  688.                flags are for.  Each will be discussed as the tutorial
  689.                proceeds.
  690.  
  691.  
  692.  
  693.  
  694.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  695.           (c) Copyright 1993-1994 DSE Software Publishing                9
  696.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  697.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  698.  
  699.                Let's say that you want a window to have a shadow, a
  700.                vertical scroll bar, and you want to drag it around with the
  701.                mouse.  In this instance, you would use the options:
  702.  
  703.                     %SHADOW OR %VSCROLLBAR OR %DRAGBAR
  704.  
  705.                You may be wondering why "OR" is used instead of the "+"
  706.                sign when adding options.  There is a very good reason.  The
  707.                "OR" key word allows you to add numbers without worrying
  708.                about adding the same number twice.  As an example:
  709.  
  710.                     1 + 2 + 8 + 8 = 19
  711.  
  712.                     1 OR 2 OR 8 OR 8 = 11
  713.  
  714.                Accidentally adding the same window flag twice could cause
  715.                unexpected results.  Using the "OR" key word simply insures
  716.                that you do not waste time looking for problems caused by
  717.                incorrectly adding the same window flags twice.
  718.  
  719.                Here's a trick to make your program much easier to read:
  720.                Place all of window flags in a variable and then pass that
  721.                variable to WINOPEN():
  722.  
  723.                     FlagsForEdna% = %SHADOW OR %VSCROLLBAR OR %DRAGBAR
  724.  
  725.                That's all for WINOPEN().  On to WINSHOW().
  726.  
  727.  
  728.           1.2.7  Displaying a Window
  729.           ─────────────────────────────────────────────────────────────────
  730.  
  731.                Creating the window was the first step.  The next step is to
  732.                get it onto the screen.  To do this you must use WINSHOW():
  733.  
  734.                     WINSHOW AuntEdna, 0, 0, 25, 80
  735.  
  736.                     1. Window handle..: AuntEDna%
  737.                     2. Screen row.....: 0
  738.                     3. Screen column..: 0
  739.                     4. Screen rows....: 25
  740.                     5. Screen columns.: 80
  741.  
  742.                The first parameter, "WINDOW HANDLE" refers to the handle
  743.                returned when the window was opened.  Remember the
  744.                discussion relating it to a "telephone number"?
  745.  
  746.                The "SCREEN ROW" and "SCREEN COL" parameters determine were
  747.                the window will be displayed.  The example shown in
  748.                TUTOR1_2.BAS might confuse you for a second, but don't let
  749.                it.  When you specify a value of 0 for the row and/or
  750.                column, the window is centered in that particular plane.
  751.  
  752.  
  753.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  754.           (c) Copyright 1993-1994 DSE Software Publishing                10
  755.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  756.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  757.  
  758.                The "SCREEN ROW" and "SCREEN COL" parameters determine how
  759.                many rows and columns of the window will be displayed.  This
  760.                too might look a little confusing because 25 and 80 are
  761.                being passed and you know darn well that the window is only
  762.                10 rows by 40 columns.  Relax.  If you pass values larger
  763.                than what is true dimensions of the window, the values are
  764.                corrected internally.  The purpose of this feature is so
  765.                that during product development, you do not have to keep
  766.                updating the call to WINSHOW() each time you change
  767.                WINOPEN().
  768.  
  769.  
  770.           1.2.8  Another way of Opening a Window
  771.           ─────────────────────────────────────────────────────────────────
  772.  
  773.                The next line introduces an alternative method of opening
  774.                and displaying a window.
  775.  
  776.                WINPOPUP() is a routine that provides the functionality of
  777.                WINOPEN() and WINSHOW() in a single call,  In fact,
  778.                internally, that is exactly what it does.
  779.  
  780.                When do you use WINPOPUP() instead of WINOPEN()?  That's
  781.                entirely up to you.  There are no real "rules" governing it
  782.                use, but there are advantages to both.
  783.  
  784.                WINOPEN() is best used when you want to display a window
  785.                with text already printed within it.  Since windows are
  786.                "virtual", you can print to them long before you actually
  787.                display them.  This way you can get the window looking prim
  788.                and proper before you show it to the whole world.  It might
  789.                save you some embarassement if you ever decide to run for
  790.                office.
  791.  
  792.                You can use WINPOPUP() when you want to quickly display an
  793.                empty window.
  794.  
  795.                Once again, there are no rules.  Use which ever is more
  796.                convenient at the time.
  797.  
  798.  
  799.           1.2.9  Printing to a Window
  800.           ─────────────────────────────────────────────────────────────────
  801.  
  802.                An empty window doesn't do you much good, so a whole slew of
  803.                printing routines have been provided for your pleasure.
  804.  
  805.                Here we use the WINPRINT() command.  Think of it as a
  806.                combination of PowerBASIC's "LOCATE", "COLOR", and "PRINT"
  807.                command.  Let's examine it:
  808.  
  809.                     WINPRINT AuntEdna, 5, 10, &H1E, "Hello Aunt Edna"
  810.  
  811.  
  812.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  813.           (c) Copyright 1993-1994 DSE Software Publishing                11
  814.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  815.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  816.  
  817.                     1. Window handle.: AuntEdna%
  818.                     2. Window row....: 5
  819.                     3. Window column.: 10
  820.                     4. Text color....: &H1E
  821.                     5. Text..........: "Hello Aunt Edna"
  822.  
  823.                The "WINDOW ROW" and "WINDOW COLUMN" parameters (you already
  824.                know what the first is) determine the row and column where
  825.                printing is to start within the window.  Bear in mind, this
  826.                is relative to the window, and not the screen itself.  You
  827.                can print text anywhere you want within the confines of the
  828.                window.
  829.  
  830.                The "COLOR" parameter works as discussed earler.  If you
  831.                don't understand what the "&H1E" means then you were naughty
  832.                and skipped the section titled "Colors, Colors Everywhere"
  833.                (section 1.2.3).  Go back and read it because you are going
  834.                to see these types of numbers throughout this tutorial.
  835.                This color happens to be bright yellow on blue.
  836.  
  837.                If you don't want to bother keeping track of the window
  838.                color, you can always use a value of '-1'.  This is always
  839.                print in the window's default color.
  840.  
  841.                The "TEXT" parameter is, well, the text itself.  Anything
  842.                you put in here gets sent to the window.
  843.  
  844.                As I said, there are other printing routines.  The notable
  845.                ones are WINWRITE() and WINWRITELN().  These work somewhat
  846.                similar to PowerBASIC's own commands as they keep track of
  847.                and print at an interal window relative cursor position.
  848.  
  849.                     WINLOCATE AuntEdna, 5, 10
  850.                     WINCOLOR AuntEdna, 14, 1
  851.                     WINWRITE AuntEdna, "Hello Aunt Edna"
  852.  
  853.                I hope they are self-explanatory.
  854.  
  855.  
  856.           1.2.10  Closing an open Window
  857.           ─────────────────────────────────────────────────────────────────
  858.  
  859.                When you are finished using a window, you may close it with
  860.                WINCLOSE().  This performs various functions.  If the window
  861.                is being displayed, it is removed from the screen.  All
  862.                memory allocated to the window is returned to the PowerBASIC
  863.                memory pool.
  864.  
  865.                Note that closing a window is quite different from hiding a
  866.                window (see WINHIDE).  When a window is hidden, it is simply
  867.                removed from view.  It can still be re-displayed with a call
  868.                to WINSHOW().  Once a window is closed, however, the window
  869.                is gone.
  870.  
  871.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  872.           (c) Copyright 1993-1994 DSE Software Publishing                12
  873.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  874.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  875.  
  876.           1.3  Customizing the "Desktop"
  877.           ─────────────────────────────────────────────────────────────────
  878.  
  879.                For the last few sections, you have been looking at programs
  880.                that use the default "desktop" settings.  Though they look
  881.                okay, you can make things look a lot better by twiddling
  882.                around with a few variables.
  883.  
  884.                The next demo, TUTOR1_3.BAS (load it now) shows how to
  885.                modify the application initialization variables.  These
  886.                variables define the look and feel of the desktop.  Let's
  887.                take quick at a few:
  888.  
  889.                     Variable Name      Purpose
  890.                     ────────────────   ───────────────────────────────────
  891.                     APP.ATTR           Color of background fill-pattern.
  892.                     APP.GRAPHICSMODE   0=text display, 1=graphics display.
  893.                     APP.GRAPHICSMOUSE  0=text mouse, 1=graphics mouse.
  894.                     APP.PATTERN        Background fill-pattern.
  895.  
  896.  
  897.           1.3.1  Text or Graphics
  898.           ─────────────────────────────────────────────────────────────────
  899.  
  900.                If you haven't ran TUTOR1_3.BAS yet, please do it now.  Do
  901.                you notice anything different?  If you have an EGA/VGA
  902.                monitor, you should be seeing a much crisper, cleaner,
  903.                (kinder & gentler too) graphical look.
  904.  
  905.                The APP.GRAPHICSMODE variable is what enabled this fine
  906.                feature.  When you set this variable to a value of 0, you
  907.                get the plain old text mode.  This is fine for regular
  908.                company, but not when you're entertaining foreign
  909.                dignitaries.  When you set it to a value of 1, you get the
  910.                "graphical mapping" mode that will win you friends.
  911.  
  912.                "Graphical mapping" is not true graphics, but it is a
  913.                strikingly close approximation.  It is achieved by taking
  914.                control of your EGA/VGA video card and "mapping" graphical
  915.                icons into the standard character set.  The end result is a
  916.                program that looks like it is running in graphics mode, but
  917.                runs with the full speed of text mode.
  918.  
  919.                There is one "quirk" that you will quickly discover when
  920.                using graphical mapping.  When you press CTRL-BREAK, or
  921.                single-step through your source, the border characters of
  922.                the PowerBASIC editor are going to look funny.  Don't worry,
  923.                your source will remain completely readable.  In a day or
  924.                so, you won't even notice it anymore.  If it does bug you
  925.                after a few days, you can always switch in to plain old text
  926.                mode while you develop your programs.
  927.  
  928.  
  929.  
  930.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  931.           (c) Copyright 1993-1994 DSE Software Publishing                13
  932.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  933.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  934.  
  935.           1.3.2  Changing the Desktop Color and Fill Pattern
  936.           ─────────────────────────────────────────────────────────────────
  937.  
  938.                You can also change the desktop color and fill pattern by
  939.                modifying the APP.ATTR and APP.PATTERN variables.  By
  940.                default, the attribute is &H17 (white on blue) and the fill
  941.                pattern character is ASCII 176 ('░').
  942.  
  943.                In TUTOR1_3.BAS, the desktop color has been changed to &H9F
  944.                (bright white on bright blue), and the fill pattern has been
  945.                changed to ASCII 32 (a space character).
  946.  
  947.                Why don't you take a few minutes to play around with the
  948.                values of these two variables.  I'll wait here till you get
  949.                back.
  950.  
  951.  
  952.           1.3.3  Adding a "Title Bar"
  953.           ─────────────────────────────────────────────────────────────────
  954.  
  955.                Next comes the APPTITLE() routine.  When a title is added to
  956.                the desktop, the entire screen is moved down one line, and
  957.                the title is displayed at the center of the first screen
  958.                line.
  959.  
  960.                You can add a title at any time, but it is best to create it
  961.                before calling APPINIT().  This way, when the desktop is
  962.                initialized, the title will come up with it.  If you want to
  963.                add (or change) the title later on, you can do that too.
  964.                You will, however, have to call APPREFRESH() to update the
  965.                desktop with the new title.
  966.  
  967.                That's it for this chapter.  Pick up your certificate at the
  968.                front desk and proceed to the next chapter.
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980.  
  981.  
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  990.           (c) Copyright 1993-1994 DSE Software Publishing                14
  991.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  992.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  993.  
  994.                                       Chapter 2
  995.  
  996.                                   EVENT MANAGEMENT
  997.  
  998.                ████████████████████████████████████████████████████████████
  999.  
  1000.           Input, Need Input!
  1001.           ─────────────────────────────────────────────────────────────────
  1002.  
  1003.                Now that you are a PB/VISION windowing guru, it's time to
  1004.                move on to ways of getting input from the user.
  1005.  
  1006.                In any program, there is more to "input" than just asking
  1007.                the user some questions.  Input could be the user typing
  1008.                something on the keyboard, or using the mouse to manipulate
  1009.                objects on the screen.
  1010.  
  1011.                With conventional programming techniques, seamless
  1012.                integration of the mouse and keyboard is an almost
  1013.                impossible task.  On the opposite side, with "event-driven"
  1014.                techniques, it becomes ridiculously easy.  You no longer
  1015.                need to respond directly to input from the user.  You
  1016.                instead respond to "messages" delivered to you by the "event
  1017.                manager".  This is how it works in PB/VISION.
  1018.  
  1019.                Event management in PB/VISION is handled entirely by a
  1020.                routine called GETEVENT().  Ideally, GETEVENT() periodically
  1021.                takes control of your program and determines if any "event"
  1022.                has happened.  If any event has indeed occurred, GETEVENT()
  1023.                returns a unique "message" indicating exactly what happened.
  1024.  
  1025.                You might now be wondering, "What is an event?".  Using the
  1026.                mouse to move a window is an event.  Pushing a button in a
  1027.                form is an event.  Selecting a menu item is an event.
  1028.                Anything you do to interact with the program is an event.
  1029.  
  1030.                A "message" is a unique numeric value indicating what type
  1031.                of event occurred.  Moving a window with the mouse will
  1032.                trigger event #206.  Pressing the <ESC> key will trigger
  1033.                event #102.  Stepping on the dogs tail with trigger a "bark
  1034.                event".  There is an event code for every possible important
  1035.                event.
  1036.  
  1037.                Keep in mind that even though an event occurs, you do not
  1038.                need to watch for it, let alone respond to it.  Most events,
  1039.                such as moving a window (#206), are trivial and most
  1040.                programs do not need to respond to them.
  1041.  
  1042.                Figure 2.1 should give you an idea of the flow control that
  1043.                GETEVENT() follows.  Don't worry, this isn't going to be on
  1044.                the test.
  1045.  
  1046.  
  1047.  
  1048.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1049.           (c) Copyright 1993-1994 DSE Software Publishing                15
  1050.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1051.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1052.  
  1053.                                         GETEVENT() IN
  1054.                                               │
  1055.                     ╔═════════════════════════│═════════════════════════╗
  1056.                     ║            ┌────────────┴────────────┐            ║
  1057.                     ║  ┌─────────┴─────────┐     ┌─────────┴─────────┐  ║
  1058.                     ║  │ Poll the Keyboard │ (a) │  Poll the Mouse   │  ║
  1059.                     ║  └─────────┬─────────┘     └─────────┬─────────┘  ║
  1060.                     ║            └────┐               ┌────┘            ║
  1061.                     ║             ┌───┴───────────────┴────┐            ║
  1062.                     ║         (b) │     Event Decoder      │            ║
  1063.                     ║             └───────────┬────────────┘            ║
  1064.                     ║             ┌───────────┴────────────┐            ║
  1065.                     ║         (c) │    Event Dispatcher    │            ║
  1066.                     ║             │   (processes events)   │            ║
  1067.                     ║             │  (spits out messages)  │            ║
  1068.                     ║             └───────────┬────────────┘            ║
  1069.                     ╚═════════════════════════│═════════════════════════╝
  1070.                                               │
  1071.                                         GETEVENT() OUT
  1072.  
  1073.                     Figure 2.1: A little "black box" called GETEVENT()
  1074.  
  1075.                As the figure shows, on entry to GETEVENT(), the keyboard
  1076.                and mouse are polled for activity.  Any activity is passed
  1077.                along to an internal subroutine that determines exactly what
  1078.                the user is attempting to do.  Once a course of action has
  1079.                been determined, the event is dispatched to the appropriate
  1080.                interface routine.  When that routine terminates, it returns
  1081.                the "message" that GETEVENT() ultimately returns to you.
  1082.  
  1083.                Strangely enough, there is even an event for a "nonevent".
  1084.                Event ID #17 indicates that absolutely nothing happened
  1085.                during this call to GETEVENT().
  1086.  
  1087.  
  1088.           2.1  Your First "Event-Driven" Program
  1089.           ─────────────────────────────────────────────────────────────────
  1090.  
  1091.                Load the file TUTOR2_1.BAS into PowerBASIC.  This program
  1092.                demonstrates the simplest possible "Event Loop".
  1093.  
  1094.  
  1095.           2.1.1  The "EVENT.BI" $INCLUDE File
  1096.           ─────────────────────────────────────────────────────────────────
  1097.  
  1098.                Near the top of the program you will notice that another
  1099.                $INCLUDE file has added.  To add event-driven control to
  1100.                your programs, you must include "EVENT.BI".
  1101.  
  1102.                Hey, what a small section!
  1103.  
  1104.  
  1105.  
  1106.  
  1107.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1108.           (c) Copyright 1993-1994 DSE Software Publishing                16
  1109.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1110.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1111.  
  1112.           2.1.2  Polling "GetEvent()" for Events
  1113.           ─────────────────────────────────────────────────────────────────
  1114.  
  1115.                As you can see, it is called an "event loop" because
  1116.                GETEVENT() must be called repeatedly (in a loop!) in order
  1117.                for your interface to function.  If you don't call
  1118.                GETEVENT(), nothing will happen.
  1119.  
  1120.                When an event occurs, an event code is returned and we
  1121.                descend through a "SELECT CASE" structure to look for code
  1122.                to respond to that particular event.
  1123.  
  1124.                In this example, two separate events are being watched for.
  1125.                The first is event #102, which is triggered when the <ESC>
  1126.                key is pressed.  When this happens, the code drops us out of
  1127.                the loop via an "EXIT DO" statement and the program
  1128.                terminates below.  Pretty boring, huh?
  1129.  
  1130.                Meanwhile, to let you know that the program is in fact
  1131.                working, the word "waiting" is continuously scrolled in the
  1132.                open window.  Don't worry, this is not a built-in feature,
  1133.                but just a response to a line of code written to handle
  1134.                event #17 (the "nothing happened" event).
  1135.  
  1136.                On with the show...
  1137.  
  1138.  
  1139.           2.2  Responding to the Keyboard
  1140.           ─────────────────────────────────────────────────────────────────
  1141.  
  1142.                As I mentioned earlier, there is an event code for just
  1143.                about every occasion.  If you pull up the PB/VISION help
  1144.                file in PowerBASIC's help system, you will find a list of
  1145.                all of the included event codes.  There are predefined codes
  1146.                for <TAB>, <SHIFT-TAB>, <F1>, and a couple dozen others.
  1147.                When anyone of these keys are pressed, GETEVENT() will
  1148.                return the corresponding event codes.  This is to save you
  1149.                from having to poll the keyboard yourself and run yourself
  1150.                silly checking for scan codes and all that other not so fun
  1151.                stuff.
  1152.  
  1153.                Load TUTOR2_2.BAS.  This program is written to watch for a
  1154.                few common (and not so common) built-in event codes.  They
  1155.                are <ESC>, <CR>, <F1>, <TAB>, <SHIFT-TAB>, <ALT-TAB>,
  1156.                <CTRL-TAB>, and <ALT-SPACE>.  Pressing any of these keys
  1157.                will display the event code generated, and the meaning of
  1158.                that event.  This program will also respond to any
  1159.                alphanumeric keys pressed.  Run the program for a few
  1160.                minutes and come back when you're ready.
  1161.  
  1162.                Just after the call to GETEVENT() is a line of code that
  1163.                prints the occurring event number each time one occurs.
  1164.                Because event #17 occurs so often, I opted to add code that
  1165.  
  1166.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1167.           (c) Copyright 1993-1994 DSE Software Publishing                17
  1168.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1169.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1170.  
  1171.                bypasses all occurrences of event #17.  If you place remarks
  1172.                in front of those lines, the screen gets updated so often
  1173.                that it gets confusing.  Try it if you want.
  1174.  
  1175.  
  1176.           2.2.1  Responding to Alpha-Numeric keys with "KEYGET"
  1177.           ─────────────────────────────────────────────────────────────────
  1178.  
  1179.                Whenever you press a key that GETEVENT() doesn't know what
  1180.                to do with, event #100 is triggered.  At the same time, a
  1181.                variable called "KEYGET%" is loaded with the value of the
  1182.                key pressed.  If the pressed key was alphanumeric, KEYGET
  1183.                will hold that key's ASCII value.  If any cursor or function
  1184.                key, or any <ALT> keys are pressed, KEYGET is loaded with an
  1185.                extended keyboard code.  You will find a list of these codes
  1186.                in the PB/VISION help screens under "Keyboard Codes".
  1187.  
  1188.                In the example we assume it is an ASCII character if KEYGET
  1189.                is less than 256, otherwise it is assumed to be an extended
  1190.                keyboard code, which we want to ignore for now.
  1191.  
  1192.  
  1193.           2.2.2  Responding to built-in Keyboard Events
  1194.           ─────────────────────────────────────────────────────────────────
  1195.  
  1196.                The next group of events are the event codes for all the
  1197.                different <TAB> key combinations and <ALT-SPACE>.  When any
  1198.                of these keys are pressed, the program responds with a line
  1199.                of text indicating which combination was pressed.
  1200.  
  1201.  
  1202.           2.2.3  Getting Help with <F1>
  1203.           ─────────────────────────────────────────────────────────────────
  1204.  
  1205.                To make adding a help system to your program as simple as
  1206.                possible, the <F1> key has been set aside as the dedicated
  1207.                "Help" key.  When you press <F1>, event #103 is triggered.
  1208.                In a couple of chapters, I'll tell you how to add a context
  1209.                sensitive help system that pops up whenever <F1> is pressed.
  1210.  
  1211.                By the way, <F1> is the only function key that has a built-
  1212.                in event code.  <F2> is _not_ going to trigger event #104 no
  1213.                matter how hard you press it.  If you want to learn how to
  1214.                trap other function keys, keep reading.
  1215.  
  1216.  
  1217.           2.3  How to create "Custom" Keyboard Event Codes
  1218.           ─────────────────────────────────────────────────────────────────
  1219.  
  1220.                In this section of the tutorial, I am going to teach you two
  1221.                of the most important features of event-driven program.  The
  1222.                first is getting input from the keyboard, and the second is
  1223.                creating your very own custom event codes.
  1224.  
  1225.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1226.           (c) Copyright 1993-1994 DSE Software Publishing                18
  1227.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1228.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1229.  
  1230.                With the multitude of event codes allowed, you would think
  1231.                that our programmers labored for years to come up with them.
  1232.                Why yes, as true as it is, there are many events that are
  1233.                not built-in.  Pressing the "A" key while wiggling your left
  1234.                pinky toe is one of them.  While this may be important to
  1235.                some programmers, it is not important to most.  For us to
  1236.                include this as part of the package would only hinder
  1237.                programmers who don't want that feature.  By now you must be
  1238.                wondering what in the world I am talking about.
  1239.  
  1240.                Let's say that you want to detect when the user of your
  1241.                program presses <ALT-X>.  In most programs this indicates
  1242.                that you would like to terminate execution of the program.
  1243.                Well, <ALT-X> doesn't have a event code for this key
  1244.                combination.  WHAT ARE YOU GOING TO DO?
  1245.  
  1246.                The answer is that you need to create a "custom event code".
  1247.                In this section, I'll show you how to create custom keyboard
  1248.                event codes.  Following sections will show you how to create
  1249.                custom menu, form, and status bar event codes.
  1250.  
  1251.                To get started, load TUTOR2_3.BAS.
  1252.  
  1253.  
  1254.           2.3.1  Defining a few Custom Event Codes
  1255.           ─────────────────────────────────────────────────────────────────
  1256.  
  1257.                The first step in creating a custom event code is figuring
  1258.                out what the event code numbers will be.  PB/VISION's
  1259.                internal event codes never go above 1000, so seems like a
  1260.                good starting point.
  1261.  
  1262.                At the head of TUTOR2_3.BAS, four custom event codes are
  1263.                defined.  Since remembering names are a lot easier than
  1264.                remembering numbers, I have assigned the event numbers to a
  1265.                few constants.
  1266.  
  1267.                     %cmF3 = 1001
  1268.                     %cmF4 = 1002
  1269.                     %cmAltX = 1003
  1270.                     %cmPookie = 1004
  1271.  
  1272.                As you might expect, the custom events created in this
  1273.                example will be triggered when the user presses <F3>, <F4>,
  1274.                and <ALT-X>.
  1275.  
  1276.                You must be wondering what "%cmPookie" is for.  It's to
  1277.                prove a point.  The names you use for the constants are
  1278.                purely arbitrary.  The "F3" in "%cmF3" does nothing to
  1279.                affect the code.  Nothing.  It's just easier to remember.  A
  1280.                "%cmPookie" event is triggered with <ALT-P>.  It could
  1281.                easily be relabeled "%cmAltP".
  1282.  
  1283.  
  1284.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1285.           (c) Copyright 1993-1994 DSE Software Publishing                19
  1286.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1287.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1288.  
  1289.                Incidentally, "Pookie" was the nickname of my friend Ross's
  1290.                sister when I was a kid in Detroit.  I think her real name
  1291.                was Sherry.
  1292.  
  1293.  
  1294.           2.3.2  Adding the Custom Events
  1295.           ─────────────────────────────────────────────────────────────────
  1296.  
  1297.                A little further down the code is where the custom events
  1298.                get added to  the list of events that GETEVENT() watches
  1299.                for.  This is the purpose of HOTKEYADD().  It lets you
  1300.                assign an event code to a particular keyboard key.  When the
  1301.                user presses the key, it triggers the corresponding event
  1302.                number.
  1303.  
  1304.                The first line:
  1305.  
  1306.                     HOTKEYADD &H3D00, %cmF3
  1307.  
  1308.                assigns the "%cmF3" event to the <F3>.  "&H3D00" is the
  1309.                extended keyboard code for the <F3> key.  The rest of the
  1310.                calls work the same way.
  1311.  
  1312.                If you want to find a list of the possible extended keyboard
  1313.                codes, bring up the PB/VISION help system and select
  1314.                "Keyboard Codes".
  1315.  
  1316.  
  1317.           2.3.3  Responding to Custom Events
  1318.           ─────────────────────────────────────────────────────────────────
  1319.  
  1320.                You might be wondering what these custom events will
  1321.                accomplish.  By looking at the code, you will see that <F3>
  1322.                prints "Hello, World!" in the top window; <F4> brings the
  1323.                next logical window to the top; <ALT-X> terminates the
  1324.                program; and <ALT-P> says "Hi" to my long lost friend's
  1325.                older sister.
  1326.  
  1327.  
  1328.           2.4  Of Mice and Windows
  1329.           ─────────────────────────────────────────────────────────────────
  1330.  
  1331.                A major part of event-driven programming is the ability  to
  1332.                use a mouse to control the interface.  That's what this
  1333.                section is about.  To get started, load TUTOR2_4.BAS.
  1334.  
  1335.                In this example, the windows can be dragged about the screen
  1336.                by positioning the mouse cursor on the top line of the
  1337.                window, and holding the left mouse button down, and moving
  1338.                the mouse hither and yon (that means "here and there" for
  1339.                those of you in Rio Linda).  The window can also be re-sized
  1340.                by grabbing the bottom left edge with the mouse and moving
  1341.                it about in the same manner.
  1342.  
  1343.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1344.           (c) Copyright 1993-1994 DSE Software Publishing                20
  1345.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1346.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1347.  
  1348.                Moving a window with the mouse triggers event #206, re-
  1349.                sizing one triggers event #207, and simply selecting one
  1350.                triggers event #202.  There are other mouse/window events,
  1351.                but you can look them up in the docs.
  1352.  
  1353.                A word of warning to advanced programmers.  Never attempt to
  1354.                mix in any of your own mouse routines.  It will cause your
  1355.                computer to explode!  Just kidding!  But seriously, using
  1356.                non-PB/VISION mouse routine will most likely cause the mouse
  1357.                to lock up.
  1358.  
  1359.  
  1360.           2.4.1  Selecting the Mouse Cursor Style
  1361.           ─────────────────────────────────────────────────────────────────
  1362.  
  1363.                Before initializing the mouse routines, you must determine
  1364.                what type of mouse cursor you want, text or graphical.  The
  1365.                text mouse gives you the familiar block character mouse, and
  1366.                the graphical cursor gives you that, well, graphical look.
  1367.  
  1368.                The purpose of the "APP.GRAPHICSMOUSE" variable is to
  1369.                determine which one you want.  For text, use a value of 0,
  1370.                and for graphical, use a value of 1.
  1371.  
  1372.                During development of your program, it is best to use the
  1373.                text mouse.  If you happen to insert a breakpoint in your
  1374.                code while the graphical mouse is enabled, you will get an
  1375.                ugly, though harmless, blob of characters for your mouse
  1376.                cursor.  It's hideous and scares farm animals.  When you are
  1377.                ready to compile your program to disk, you may then enable
  1378.                the graphical cursor.
  1379.  
  1380.  
  1381.           2.4.2  Making your program "Mouse Aware"
  1382.           ─────────────────────────────────────────────────────────────────
  1383.  
  1384.                The next step is to initialize the mouse and turn it on.
  1385.  
  1386.                MOUSEINIT() is the magic function that accomplishes this
  1387.                feat.  When called, it will not only enable the mouse, but
  1388.                it will tell you how many buttons are on it.  This is always
  1389.                a good topic of discussion at cocktail parties.  The more
  1390.                buttons you have, the more affluent you are.
  1391.  
  1392.                If a mouse is found, MOUSEINIT() will return some positive
  1393.                value. If it returns a value of 0, that means you don't have
  1394.                a mouse and you probably have no idea what I am talking
  1395.                about right now.
  1396.  
  1397.                Once the mouse is initialized, you can make it visible with
  1398.                a call to MOUSECURSORON().  Until then, it is invisible and
  1399.                disabled.
  1400.  
  1401.  
  1402.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1403.           (c) Copyright 1993-1994 DSE Software Publishing                21
  1404.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1405.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1406.  
  1407.                By the way, for any of this to work, you must include
  1408.                "MOUSE.BI" in your list of $INCLUDE files (see line 10).
  1409.  
  1410.  
  1411.           2.4.3  Making Windows Mouse Aware
  1412.           ─────────────────────────────────────────────────────────────────
  1413.  
  1414.                Just because a program is "mouse aware", doesn't mean the
  1415.                windows are mouse aware.  You have to turn on a couple of
  1416.                options in each window to let the event manager know how far
  1417.                you will let the mouse go with the windows.
  1418.  
  1419.                For purposes of this example, the windows should be dragable
  1420.                and re-sizable.  Adding these traits is a simple as adding
  1421.                the "%DRAGBAR" and "%RESIZE" flags to the list of window
  1422.                flags.
  1423.  
  1424.  
  1425.           2.4.4  Responding to "Mouse Events"
  1426.           ─────────────────────────────────────────────────────────────────
  1427.  
  1428.                Take a moment to run the program.   When you move the window
  1429.                (event #206) the program displays some text (in the window,
  1430.                of course) to call attention to it's unwavering fondness for
  1431.                you.  Re-sizing the window (event #207) displays some other
  1432.                funny statement which hasn't been determined at press time.
  1433.                Simply clicking the window will display a third statement
  1434.                that doesn't appear to be funny at all.
  1435.  
  1436.                For a list of other mouse events, pull up the "Event Codes"
  1437.                help screen in the PowerBASIC editor.
  1438.  
  1439.  
  1440.  
  1441.  
  1442.  
  1443.  
  1444.  
  1445.  
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454.  
  1455.  
  1456.  
  1457.  
  1458.  
  1459.  
  1460.  
  1461.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1462.           (c) Copyright 1993-1994 DSE Software Publishing                22
  1463.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1464.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1465.  
  1466.                                       Chapter 3
  1467.  
  1468.                            ADVANCED PROGRAMMING TECHNIQUES
  1469.  
  1470.                ████████████████████████████████████████████████████████████
  1471.  
  1472.  
  1473.           3.1  Multi-Threading made easy.
  1474.           ─────────────────────────────────────────────────────────────────
  1475.  
  1476.                If you have seen the PB/WORKSHOP demo (or if you own the
  1477.                real thing), you may be wondering how there can be so many
  1478.                data entry forms on the screen at a single time and that all
  1479.                of them seem to be active.
  1480.  
  1481.                This is accomplished through "multi-threading".  STOP!
  1482.                Don't run away.  This is a $10.00 word for a 10 cent
  1483.                concept, a sheep in wolves clothing, something so simple
  1484.                that even a politician could understand.  You get the point.
  1485.                In five (maybe 10) minutes you're going to be an expert on
  1486.                the subject.
  1487.  
  1488.                In a normal program GETEVENT() returns every event back to
  1489.                you right after the event occurs.  Simplifying Figure 2.1
  1490.                shown way at the beginning of the tutorial, events are
  1491.                processed as shown in Figure 3.1.
  1492.  
  1493.                                    EVENT COMES IN
  1494.                                    ──────┬───────
  1495.                                          │
  1496.                               ┌──────────┴──────────┐
  1497.                               │ GETEVENT() FUNCTION │
  1498.                               └──────────┬──────────┘
  1499.                                          │
  1500.                                 ─────────┴──────────
  1501.                                 EVENT CODE COMES OUT
  1502.  
  1503.                        Figure 3.1: Simplified GETEVENT() flowchart.
  1504.  
  1505.                Whenever the user does something important (like selecting a
  1506.                menu item or pressing a key), the event code is returned to
  1507.                you immediately by GETEVENT().  Simple, right?
  1508.  
  1509.                When you multi-thread a window, menu, or form (objects), you
  1510.                add an intermediate function in the middle of the whole
  1511.                process.
  1512.  
  1513.  
  1514.  
  1515.  
  1516.  
  1517.  
  1518.  
  1519.  
  1520.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1521.           (c) Copyright 1993-1994 DSE Software Publishing                23
  1522.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1523.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1524.  
  1525.                                    EVENT COMES IN
  1526.                                    ──────┬───────
  1527.                                          │
  1528.                                ┌─────────┴──────────┐
  1529.                                │ YOUR FUNCTION HERE │
  1530.                                └─────────┬──────────┘
  1531.                                          │
  1532.                               ┌──────────┴──────────┐
  1533.                               │ GETEVENT() FUNCTION │
  1534.                               └──────────┬──────────┘
  1535.                                          │
  1536.                                ──────────┴─────────
  1537.                                EVENT CODE COMES OUT
  1538.  
  1539.                       Figure 3.2: GETEVENT() with "Multi-Threading".
  1540.  
  1541.                This time around, your own function gets called just before
  1542.                GETEVENT() returns the event code.  The only time your
  1543.                function gets called is when you act directly upon the
  1544.                window it is assigned to.  Because of this, you can assign
  1545.                different functions to different objects as shown in Figure
  1546.                3.3.  Each function will only be called when you do
  1547.                something to the object it belongs to.
  1548.  
  1549.                                       EVENT COMES IN
  1550.                                       ──────┬───────
  1551.                               ┌─────────────┴─────────────┐
  1552.                     ┌─────────┴────────────┐   ┌──────────┴───────────┐
  1553.                     │  YOUR FUNCTION HERE  │   │ AND ANOTHER ONE HERE │
  1554.                     └─────────┬────────────┘   └──────────┬───────────┘
  1555.                               └─────────────┬─────────────┘
  1556.                                  ┌──────────┴──────────┐
  1557.                                  │ GETEVENT() FUNCTION │
  1558.                                  └──────────┬──────────┘
  1559.                                    ─────────┴──────────
  1560.                                    EVENT CODE COMES OUT
  1561.  
  1562.                      Figure 3.3: "Multi-Threading" multiple objects.
  1563.  
  1564.                So how does this all relate when it comes to real programs?
  1565.                That is the purpose of WININSTALLCODE(), and the subject of
  1566.                next couple of sections.
  1567.  
  1568.                To get started, load TUTOR3_1.BAS
  1569.  
  1570.  
  1571.           3.1.1  Assigning Code to a Window.
  1572.           ─────────────────────────────────────────────────────────────────
  1573.  
  1574.                Here we open a window just like all of the other windows
  1575.                opened so far.  Nothing special so far.
  1576.  
  1577.  
  1578.  
  1579.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1580.           (c) Copyright 1993-1994 DSE Software Publishing                24
  1581.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1582.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1583.  
  1584.                The big step comes with WININSTALLCODE().  Here we must pass
  1585.                it the handle of the window, as well as the address of the
  1586.                function that will be assigned to the window.
  1587.  
  1588.                     WININSTALLCODE win1%, CODESEG(YourRoutine),
  1589.                                              CODEPTR(YourRoutine)
  1590.  
  1591.                     1. Window handle........: win1%
  1592.                     2. Routine code segment.: CODESEG(YourRoutine)
  1593.                     3. Routine code offset..: CODEPTR(YourRoutine)
  1594.  
  1595.                If you are not familiar with CODESEG() and CODEPTR(), these
  1596.                are PowerBASIC routines that return the segment and offset
  1597.                of a function, sub, or line label.
  1598.  
  1599.                This is how the program knows what function to call when you
  1600.                do something to a particular window.
  1601.  
  1602.  
  1603.           3.1.2  Syntax of a Window Subroutine.
  1604.           ─────────────────────────────────────────────────────────────────
  1605.  
  1606.                When your subroutine gets called, several parameters are
  1607.                passed  to it.  These are all passed by value (BYVAL).
  1608.  
  1609.                     FUNCTION YOURROUTINE% (WinHandle%, EventNo%, Parm1%,
  1610.                                                                    Parm2%)
  1611.  
  1612.                The first parameter is always the window's handle.  Since is
  1613.                it possible to assign the same function to different
  1614.                windows, it is always nice to know which window is being
  1615.                acted upon.
  1616.  
  1617.                The second parameter is the event code.  This is the same
  1618.                code that GETEVENT() would have returned had you not
  1619.                installed the subroutine.
  1620.  
  1621.                The last two parameters vary with the event code.  If you
  1622.                move the window, PARM1% and PARM2% will reflect the new row
  1623.                and column where the window was moved to.  If you re-size
  1624.                the window, PARM1% and PARM2% will reflect the new size of
  1625.                the window in rows and columns.  If you just click on the
  1626.                window, they will be the row and column within the window
  1627.                where the click occured.  Most other times, they will both
  1628.                be 0.
  1629.  
  1630.                It is important that you use this exact syntax for your
  1631.                window subroutine.  You can cut and paste a generic template
  1632.                from PB/VISION's help file by pressing SHIFT-F1 and
  1633.                selecting "WinInstallCode() Template".
  1634.  
  1635.  
  1636.  
  1637.  
  1638.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1639.           (c) Copyright 1993-1994 DSE Software Publishing                25
  1640.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1641.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1642.  
  1643.           3.1.3  Processing Events in a Window Subroutine.
  1644.           ─────────────────────────────────────────────────────────────────
  1645.  
  1646.                This should look quite familiar.  Inside of your subroutine
  1647.                you  act upon the event codes just as if they had been
  1648.                returned by GETEVENT().  There is absolutely no difference.
  1649.  
  1650.                Remember, the only time this subroutine gets called is when
  1651.                this window gets acted upon.  You don't have to worry about
  1652.                events triggered by other windows.  Also, if you have a
  1653.                pulldown menu or status bar active, the event codes will
  1654.                _not_ be passed to your subroutine.  They will be passed to
  1655.                GETEVENT() as normal.
  1656.  
  1657.  
  1658.           3.1.4  Returning Event Codes back to GETEVENT().
  1659.           ─────────────────────────────────────────────────────────────────
  1660.  
  1661.                The final step is to return the event code back to
  1662.                GETEVENT().  Since this is a function, you just return the
  1663.                value like you would in any other function.
  1664.  
  1665.                     YourRoutine% = EventNo%
  1666.  
  1667.                Hmmmm.  This could be interesting.  If you want to, you
  1668.                could even return a different event code altogether.  In
  1669.                this example, we do just that.  Look up a few lines.  Do you
  1670.                see the "CASE 203"?  This is the event code returned when
  1671.                you click the control box on a window.  Here we intercept
  1672.                this event, and reassign "EventNo = 102".  This is the event
  1673.                code for the <ESC> key.
  1674.  
  1675.                     CASE 203
  1676.                          EventNo = 102
  1677.  
  1678.                     ...
  1679.  
  1680.                     YourRoutine% = EventNo%
  1681.  
  1682.                This way, event code 102 is returned back to the main
  1683.                GETEVENT() loop and it thinks someone pressed the <ESC> key.
  1684.  
  1685.  
  1686.           3.2  Multi-Threading Continued - A Couple of New Events.
  1687.           ─────────────────────────────────────────────────────────────────
  1688.  
  1689.                In the next TUTOR3_2.BAS you will be introduced to a couple
  1690.                of new event codes.
  1691.  
  1692.                Before examining the source code, please run the demo.
  1693.                Using the mouse, click the center of each window a couple of
  1694.                times.   Do you notice anything different?  Keep reading.
  1695.  
  1696.  
  1697.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1698.           (c) Copyright 1993-1994 DSE Software Publishing                26
  1699.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1700.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1701.  
  1702.           3.2.1  Some New Events Codes.
  1703.           ─────────────────────────────────────────────────────────────────
  1704.  
  1705.                When you switch from one window to another, _two_ event
  1706.                codes are triggered.  The first event is #200.  This event
  1707.                lets a window know that it just got focus.  The second event
  1708.                is the regular event code.  At the same time, in the other
  1709.                window, event #201 is triggered.  This lets the other window
  1710.                know that it is no longer the center of attention.
  1711.  
  1712.  
  1713.           3.3  Complex Multi-Threaded Program.
  1714.           ─────────────────────────────────────────────────────────────────
  1715.  
  1716.                When it comes down to it, multi-threading is best left to
  1717.                data entry forms and menus, but you can do some very
  1718.                interesting things to dress up a plain old window.  That is
  1719.                what will be done in this section.
  1720.  
  1721.                TUTOR3_3.BAS (load it now) shows a more realistic use of
  1722.                multi-threaded techniques to manage objects on the display.
  1723.  
  1724.                This program displays a window from which you can make a
  1725.                color selection.  When you select a color, the output window
  1726.                is re-colored with that color.  This is accomplished by
  1727.                assigning a subroutine to the selection window so that it
  1728.                responds to mouse clicks in specific parts of the window.
  1729.                Whenever one of the specific areas is clicked, such as on
  1730.                one of the color tiles, the subroutine responds accordingly.
  1731.  
  1732.  
  1733.           3.3.1  Making the Code More Readable.
  1734.           ─────────────────────────────────────────────────────────────────
  1735.  
  1736.                To make the program more readable, all of the code that
  1737.                initializes the selection window has been placed in it's own
  1738.                subroutine.  This subroutine is labeled "PENWINDOW.INIT".
  1739.                You will find it a little lower in the program source.
  1740.  
  1741.  
  1742.           3.3.2  Initializing the Selection Window.
  1743.           ─────────────────────────────────────────────────────────────────
  1744.  
  1745.                In PENWINDOW.INIT(), the selection window is opened and the
  1746.                multi-threading subroutine, PENWINDOW.ROUTINE(), is assigned
  1747.                to it.  The final call in PENWINDOW.INIT() simply calls the
  1748.                assigned subroutine once with dummy values that force it to
  1749.                initially paint the window.
  1750.  
  1751.  
  1752.  
  1753.  
  1754.  
  1755.  
  1756.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1757.           (c) Copyright 1993-1994 DSE Software Publishing                27
  1758.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1759.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1760.  
  1761.           3.3.3  Responding to Window Clicks
  1762.           ─────────────────────────────────────────────────────────────────
  1763.  
  1764.                As the program runs, clicking on the selection window will
  1765.                trigger event #202.  As you may recall, this is the "window
  1766.                click" event.  At this time, PENWINDOW.ROUTINE() gets called
  1767.                with the last two parameters signifying the row and column
  1768.                within the window where the click occurred.  In previous
  1769.                programs these two parameters were labeled "Parm1%" and
  1770.                "Parm2%".
  1771.  
  1772.                A little lower in the code, the row and column get parsed
  1773.                through a SELECT CASE structure to figure out exactly what
  1774.                color was desired.  Next the output window gets re-colored.
  1775.  
  1776.  
  1777.           3.3.4  Returning a Modified Event Code
  1778.           ─────────────────────────────────────────────────────────────────
  1779.  
  1780.                To inform the main event loop (and you) that the color was
  1781.                changed, a custom event code labeled "%cmColorChange" was
  1782.                defined at the beginning of the program.  After the window
  1783.                is re-colored, the "EventNo%" parameter is changed to
  1784.                reflect the color change and this value gets returned back
  1785.                to GETEVENT().  At that time, some text gets printed to the
  1786.                output window in the new color.
  1787.  
  1788.  
  1789.           3.4  Child Menus and Forms without Overkill.
  1790.           ─────────────────────────────────────────────────────────────────
  1791.  
  1792.                Now onto a new subject...
  1793.  
  1794.                There are many times you want to be able to bring up a menu
  1795.                or form, make a selection, and then have it go just away.
  1796.                Multi-threading is severe overkill is this case.
  1797.  
  1798.                The best way to structure this is to put the entire second
  1799.                object in its own subroutine.  The following routine should
  1800.                serve as a template:
  1801.  
  1802.                     SUB SecondObject
  1803.  
  1804.                          saveState% = WINLOCKSTATE     ' see text below
  1805.  
  1806.                          ' code to open and display object goes here
  1807.  
  1808.                          WINLOCKALL WINGET             ' see text below
  1809.  
  1810.                          DO
  1811.  
  1812.                               SELECT CASE GETEVENT(0)
  1813.  
  1814.  
  1815.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1816.           (c) Copyright 1993-1994 DSE Software Publishing                28
  1817.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1818.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1819.  
  1820.                                    CASE 102       ' esc key
  1821.                                         EXIT LOOP
  1822.  
  1823.                                    CASE ELSE
  1824.  
  1825.                               END SELECT
  1826.  
  1827.                          LOOP
  1828.  
  1829.                          ' code to hide and close object goes here
  1830.  
  1831.                          WINLOCKRESTORE saveState%     ' see text below
  1832.  
  1833.                     END SUB
  1834.  
  1835.                There are three very important routines that must be called
  1836.                when bringing up a secondary object.
  1837.  
  1838.                     1.   The WINLOCKSTATE%() function returns information
  1839.                          about the internal state of the window management
  1840.                          code.  You must save this information in an
  1841.                          INTEGER variable _before_ bringing up the second
  1842.                          object.
  1843.  
  1844.                     2.   WINLOCKALL(WINGET) completely locks the top most
  1845.                          object in place and does not permit selection of
  1846.                          any other screen object.  This is called _after_
  1847.                          the new object is displayed.
  1848.  
  1849.                     3.   WINLOCKRESTORE() must be called after the second
  1850.                          object has been closed.  This puts the window
  1851.                          manager back to its original state.  You should
  1852.                          pass it the same variable you used for
  1853.                          WINLOCKSTATE%().
  1854.  
  1855.  
  1856.           3.5  Background Tasking
  1857.           ─────────────────────────────────────────────────────────────────
  1858.  
  1859.                For those of you developing communications programs or
  1860.                programs that perform a lot of report printing, "Background
  1861.                Tasking" becomes a necessity.
  1862.  
  1863.                With communications programs it is important that you check
  1864.                the input buffer on a regular basis.  If you do not, the
  1865.                buffer fills up and you either lose data or communications
  1866.                is halted.  When it comes to printing, most programs tie up
  1867.                the computer until the printing is completed.
  1868.  
  1869.                None of this is true if you plan your program carefully and
  1870.                use PB/VISION's background tasking routine
  1871.                TIMERINSTALLCODE().
  1872.  
  1873.  
  1874.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1875.           (c) Copyright 1993-1994 DSE Software Publishing                29
  1876.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1877.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1878.  
  1879.                As the name implies, TIMERINSTALLCODE() allows you to create
  1880.                a special routine that will be called automatically up to 18
  1881.                times per second.  While this is not a true "interrupt
  1882.                handler" as most assembly programmers would know it, it
  1883.                suits the purpose quite well.
  1884.  
  1885.                To use the routine, you must first create the function that
  1886.                will be called:
  1887.  
  1888.                     FUNCTION MyTask% (BYVAL UpdateSafe%)
  1889.  
  1890.                          SOUND 20000, .1          ' sound a 'tick'
  1891.  
  1892.                          MyTask% = 0
  1893.  
  1894.                     END FUNCTION
  1895.  
  1896.                When PB/VISION internally calls your routine, it passes a
  1897.                single parameter that tells whether it is safe to update the
  1898.                screen.  If '1' is passed, it is safe to perform _any_
  1899.                PB/VISION specific screen (desktop) operation.  If '0' is
  1900.                passed, do not do anything that will update the screen
  1901.                (desktop).
  1902.  
  1903.                Since MyTask%() is a function, it can return a value.  This
  1904.                value will be returned by GETEVENT().  If you were to change
  1905.                the above to "MyTask% = 102", GETEVENT() would also return
  1906.                102.  You would be left thinking a ghost pressed the <ESC>
  1907.                key since 102 is the <ESC> key event.
  1908.  
  1909.                There is _one_ exception to the last paragraph.  The only
  1910.                time your routine will return a value back to GETEVENT() is
  1911.                when the "UpdateSafe%" parameter has a value of '1'.  It is
  1912.                ignored if "UpdateSafe%" is '0'.
  1913.  
  1914.                MTIMER.BAS and SPOOLER.BAS are two programs that fully
  1915.                demonstrate the mechanics of the routine.
  1916.  
  1917.  
  1918.           3.6  Making programs smaller with "Stub" Files.
  1919.           ─────────────────────────────────────────────────────────────────
  1920.  
  1921.                On those rare occasions you feel you can do with the fancy-
  1922.                schmansy graphics mapping and/or rodent control, several
  1923.                special stub files have been included.
  1924.  
  1925.  
  1926.           3.6.1  The "NOGRAPH.OBJ" and "NOTEXT.OBJ" Stub Files.
  1927.           ─────────────────────────────────────────────────────────────────
  1928.  
  1929.                Adding this module to you program will remove all support
  1930.                for graphics mapping and the arrow style mouse.  It will
  1931.                trim about 8K off the size of your program.
  1932.  
  1933.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1934.           (c) Copyright 1993-1994 DSE Software Publishing                30
  1935.           PB/VISION(tm) LITE 1.00 - TUTORIAL
  1936.           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  1937.  
  1938.                To use it, just $LINK it in right below the "%ISPBU"
  1939.                assignment in the main module of your program:
  1940.  
  1941.                     %ISPBU = 0
  1942.                     $LINK "NOGRAPH.OBJ"
  1943.  
  1944.                Before the call to APPINIT() you should add:
  1945.  
  1946.                     app.graphicsmode = 0
  1947.                     app.graphicsmouse = 0
  1948.  
  1949.                If you are real daring and only want to support EGA/VGA
  1950.                graphics mapping, you can perform the exact opposit with:
  1951.  
  1952.                     %ISPBU = 0
  1953.                     $LINK "NOTEXT.OBJ"
  1954.  
  1955.                and then:
  1956.  
  1957.                     app.graphicsmode = 1
  1958.                     app.graphicsmouse = 1
  1959.  
  1960.  
  1961.           3.6.2  The "NOMOUSE.OBJ" Stub File
  1962.           ─────────────────────────────────────────────────────────────────
  1963.  
  1964.                To remove all mouse support from PB/VISION you can link in
  1965.                "NOMOUSE.OBJ".  It's job is to make sure that all of
  1966.                PB/VISION's internal mouse calls have some where to go.
  1967.                This will trim about 4K off your program size.
  1968.  
  1969.                To use it, just $LINK it in right below the "%ISPBU"
  1970.                assignment in the main module of your program.
  1971.  
  1972.                     %ISPBU = 0
  1973.                     $LINK "NOMOUSE.OBJ"
  1974.  
  1975.  
  1976.  
  1977.  
  1978.  
  1979.  
  1980.  
  1981.  
  1982.  
  1983.  
  1984.  
  1985.  
  1986.  
  1987.  
  1988.  
  1989.  
  1990.  
  1991.  
  1992.           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  1993.           (c) Copyright 1993-1994 DSE Software Publishing                31
  1994.