home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 21 / CD_ASCQ_21_040595.iso / dos / prg / pas / tvgr70 / beginner.doc < prev    next >
Text File  |  1995-01-08  |  34KB  |  977 lines

  1.  
  2.  
  3.  
  4. 11/22/94
  5.  
  6. Beginner's Turbo Vision/TVGraphic Tutorial
  7.  
  8. This file attempts to give a brief once over of areas that  trou-
  9. ble  Pascal  programmers  when  working  with  Turbo  Vision  and
  10. TVGraphic. (TV is used when referring to both.)
  11.  
  12.  
  13. Contents
  14.   READ THIS BOOK
  15.   Square One - Event Driven
  16.   The Transition to TV
  17.   Basics on Pointers in TV
  18.   Safety when constructing objects
  19.   Destructing Objects - Dispose versus Done
  20.   PStrings and Memory Overwrites
  21.   TV/TVGraphic - Order of Views
  22.   Inserting Views - Assumptions, Where, How
  23.   DrawView versus Draw
  24.   Color Palettes
  25.   Communication Among Views in a Dialog Box (TDialog)
  26.  
  27.  
  28. READ THIS BOOK
  29. Finally a book that really clarifies how to use TV. Starts  right
  30. from the beginning. Goes through the complex. Not just a copy  of
  31. the words in the Borland documentation. Published June 1994.
  32.  
  33.   You want:    Programming with Turbo Vision
  34.                B. Watson
  35.                M&T Books
  36.                ISBN 1-55851-399-X
  37.  
  38.  
  39. Square One
  40.  
  41. A TV application consists of
  42.         begin
  43.           MyApplication.Init
  44.           MyApplication.Run
  45.           MyApplication.Done
  46.         end.        - that's all.
  47.  
  48. So except for initialization and clean up, all the code  executes
  49. within Run. Run calls MyApplication.GetEvent and then  MyApplica-
  50. tion.HandleEvent repeatedly in a loop. (This loop only terminates
  51. when the program ends.) GetEvent is often inherited from TProgram
  52. and used as is. It fetches Events: keystrokes, mouse actions  and
  53. events  (referred to as Commands) generated by Menus, Dialog  box
  54. buttons, etc. The Event is then passed to  MyApplication.HandleE-
  55. vent.
  56.  
  57. MyApplication.HandleEvent  calls TProgram.HandleEvent which  then
  58. calls  the  HandleEvents for all the views inserted  directly  or
  59.  
  60.  
  61.                                 1
  62.  
  63.  
  64.  
  65. indirectly into MyApplication. If the Event is from the mouse, it
  66. is  passed  to  the view the mouse cursor  is  within.  Otherwise
  67. events  are  usually passed to the "selected" view. That  is  the
  68. view  that is the focus of the user's (and the program's)  atten-
  69. tion  at  this moment. (Views = objects visible on the  screen  :
  70. Menus, DeskTop, Windows, etc.  Inserting a view into the DeskTop,
  71. Window, Dialog, etc. makes the view visible and causes Events  to
  72. be passed to the view's HandleEvent.).
  73.  
  74. Your  job is to write the HandleEvents for the views  you  create
  75. and for standard views you want to modify. Within these  HandleE-
  76. vents,  you select which Events to respond to and then call  your
  77. code  written  for  that Event. Each block of code  you  want  to
  78. execute  will  be triggered directly or indirectly by  an  Event.
  79. Note  that your HandleEvent must identify and then respond to  at
  80. least  one type of Event to have any effect on the program.  Also
  81. note  that you almost always call the HandleEvent of your  view's
  82. ancestor  object somewhere in your HandleEvent. The call  to  the
  83. ancestor's HandleEvent calls the ancestor's code/behavior.
  84.  
  85. This is called Event Driven programming. If no events are  gener-
  86. ated by the user or by your code, then TV will sit idle. Forever.
  87.  
  88. A consequence of Event Driven programming is that the sequence in
  89. which  the program executes is not as rigidly defined as in  con-
  90. ventional  programming  style. Also you will most often  issue  a
  91. Command Event to call code in one view from another, rather  than
  92. calling the code directly. It will take a while for this to  seem
  93. natural.
  94.  
  95. HandleEvents  of  standard views make standard calls  to  various
  96. methods. So you can also modify a view's behavior just by writing
  97. a  new  or modified version of the called method. This  is  often
  98. simpler than modifying HandleEvent.
  99.  
  100.  
  101. The Transition to TV
  102.  
  103. Three  things combine to make the transition to Turbo Vision  and
  104. similar environments difficult - Object orientation, event driven
  105. behavior  and pointers. Tutorials on objects, event driven  envi-
  106. ronments  and  pointers are in Borland's doc but  thinking  Turbo
  107. Vision "pointer" isn't. That's here.
  108.  
  109. The  reward for learning Turbo Vision and TVGraphic is  the  high
  110. quality  of programs you can turn out. There is far more to  them
  111. than  just a pretty face. Menus, windows and screen  redraws  are
  112. handled  fully automatically. The event driven framework  is  so-
  113. phisticated  and  flexible. Skim the Borland manuals  on  Collec-
  114. tions,  Streams and Resources. These are very powerful data  han-
  115. dling  tools  and they are integrated in. No  longer  must  files
  116. contain  records of the same length unless working at the  binary
  117. level.  Collections  provide this benefit and more for  items  in
  118. memory. Much of this new Pascal power comes from pointers.
  119.  
  120.  
  121.  
  122.                                 2
  123.  
  124.  
  125.  
  126. BASICS ON POINTERS IN TV
  127.   In  much traditional Pascal programming, the idea was to  avoid
  128. using pointers unless absolutely necessary. This was a virtue  to
  129. the extent that it avoided the many bugs and system crashes which
  130. pointers lend themselves to. However pointers are the only way to
  131. access  the true power of object orientation in Pascal  and  C++.
  132. Only  by using pointers to objects can you write code that  works
  133. with an object type the user selects at run time! And Yes, Pascal
  134. object pointers are typed, but an object pointer can point to  an
  135. object of its own type or to an object of a descendant type. Your
  136. code  will work with either at run time. See the section  of  the
  137. Pascal manuals that has a general tutorial on pointers.
  138.  
  139.   If you haven't worked with pointers and look at the source code
  140. for  Turbo Vision, parts of it will be almost unrecognizable.  In
  141. fact  these  parts  of Turbo Vision don't feel as  if  they  were
  142. written by a Pascal programmer - more like a pointer maniac.
  143.  
  144.   Let's look at ways of thinking that may help.
  145.  
  146.   A  pointer is just the numerical address (location) of  a  data
  147. structure (char,integer,record,object instance) in memory. It  is
  148. the way programs, at the internal level, actually know where they
  149. put their variables in memory.
  150.  
  151. Object Types (definitions) are usually called "objects" in Pascal
  152. (they are called classes in other object oriented languages).  An
  153. object Type is similar to a Record Type in that it contains  data
  154. fields but it also defines Functions and Procedures which  belong
  155. to  the object type. Next there are individual object  variables,
  156. each  created in its own space in memory. These are  also  called
  157. objects.  Confusing. Finally there can be a pointer Type  defined
  158. for any particular object Type. Pascal will enforce type checking
  159. to be sure all these things match.
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.                                 3
  184.  
  185.  
  186.  
  187.   Turbo Vision speak:
  188.  
  189. 1.  Assume in TV that there is a pointer type defined  for  every
  190. object type. (Follow this practice yourself.)
  191.  
  192.     TView - T indicates an object type  (a class)
  193.     PView - P indicates a pointer type. PView type pointers point
  194.                to TView type objects (and their descendants).
  195.  
  196.   example
  197.      type           {Pascal allows this out of order  declaration
  198.                        within a single Type statement}
  199.        PView = ^TView
  200.        TView = Object
  201.                  Owner : PGroup;
  202.                  Size : TPoint; {TPoint is a record with fields
  203.                                        x,y}
  204.                   ...
  205.                   ...
  206.                  end;
  207.  
  208.  
  209. !  NOTE THE ^ SYMBOL. It is Critical to Understanding !
  210.  
  211.      With  pointers and variables (and their types), the  ^  lets
  212.      you grab one if you know the name of the other.
  213.  
  214.            ^Variable   is a pointer to Variable
  215.             Pointer^   is the variable that Pointer points to.
  216.  
  217.          Think about this for a minute.
  218.  
  219. 2.   Whenever you see a variable representing an object in  Turbo
  220. Vision,  EXPECT  it is a pointer to the object (rather  than  the
  221. object itself). This is correct 90-99% of the time.
  222.  
  223.        example
  224.          var
  225.            MyView : PView;
  226.            x      : integer;
  227.          begin
  228.            MyView := New(PView, Init(.......));
  229.            x := MyView^.Size.x;
  230.  
  231. MyView  is  a pointer variable - commonly called a  pointer.  The
  232. first  statement after Begin creates an object of type  TView  in
  233. memory  and  then assigns the address of this memory  to  pointer
  234. MyView.
  235.  
  236. Turbo  Vision's  TView has a field Size which contains  a  record
  237. with x and y fields.
  238.  
  239.   So     "Size.x"      by itself should look familiar.
  240.  
  241.   What may not look familiar is   MyView^  .
  242.  
  243.  
  244.                                 4
  245.  
  246.  
  247.  
  248.  
  249.   And how about MyView^.Owner^.Size.x  ?
  250.  
  251. Welcome to Turbo Vision and the land of pointer.
  252.  
  253.   Take a deep breath. Exhale.
  254.   Ingest your favorite mood altering substances.
  255.   Say: It will all make sense.
  256.  
  257. We said MyView^ meant the variable (object) pointed at by MyView
  258.  
  259.   so  MyView^.Size
  260.        says that Size is a field in variable (object) MyView^.
  261.        Remember MyView^ is an object of type TView.
  262.        (Think of the object as a Record with various fields)
  263.  
  264.   In TV, each TView has a field Owner which is of type PGroup.
  265.   TGroups are descended from TViews.
  266.  
  267.  
  268.   then  MyView^.Owner^.Size
  269.  
  270.      will be the Size field of the Owner^ (TV jargon) of MyView^.
  271.        That is, Owner is a PView pointer. So Owner^ is another
  272.        object of a type descended from TView.
  273.        It therefore has ITS OWN Size field!
  274.        THAT Size field is:    MyView^.Owner^.Size !
  275.  
  276. 3.        See >    MyView^.Owner^.Size
  277.  
  278.             Think >    MyView's Owner's Size
  279.  
  280.   Since  Size  is just a record type variable, the  x   field  of
  281. Size is as usual -  Size.x
  282.  
  283.   Again,  MyView and Owner are the pointers, MyView^  and  Owner^
  284. are the actual objects.
  285.  
  286. If you can start to think as in 3 above, you are over the hardest
  287. part.
  288.  
  289. Take a Break
  290.  
  291.  
  292. SAFETY WHEN CONSTRUCTING OBJECTS
  293.  
  294. HOW TO CRASH YOUR COMPUTER, two ways, no sweat
  295.  
  296.     MyView^.Owner^.Size
  297.  
  298.   When you initialize an object in TV, all the fields are set  to
  299. 0  (Magic done in TObject.Init). This includes pointer  variables
  300. like Owner in MyView/TView. This is referred to as a nil  pointer
  301. - it doesn't point at anything real.
  302.  
  303.  
  304.  
  305.                                 5
  306.  
  307.  
  308.  
  309. BUT  it  still acts as a pointer. If Owner is nil and  your  code
  310. attempts to read Owner^.Size.x, it will find a value. Not one you
  311. can predict but not usually dangerous.
  312.  
  313. However  there are functions and procedures attached to  a  TView
  314. object and it is often necessary to call them through an object's
  315. pointer. It is very common for TV code to call say
  316.  
  317.                     Owner^.MoveTo
  318.  
  319. Which tells object Owner^ to execute its MoveTo procedure  (where
  320. MoveTo  is a procedure defined in object type TView). If  pointer
  321. Owner  is nil, the call proceeds anyway (the compiler  knows  the
  322. type of Owner and so can find most of its methods). But if MoveTo
  323. is  a  "virtual" method (see Borland Doc) or if  MoveTo  in  turn
  324. calls  any virtual methods, then Pascal will jump to  the  method
  325. based  on  a table of procedure starting addresses  near  address
  326. nil=0 of memory. Wherever an object's virtual method table is, it
  327. is guaranteed not to be there. Boom.
  328.  
  329. >>>  Calls  to virtual methods of uninitialized  objects  can  be
  330. trapped  as a runtime error if the compiler's Range  checking  is
  331. turned on. However no errors will be found if there are no virtu-
  332. al methods for the object.
  333.  
  334. The  other common way to crash also comes from pointer fields  in
  335. objects. Say you sometimes create a TCollection dynamically using
  336. NEW  and assign it to the pointer MyView.CollectionPtr but  some-
  337. times you do not. When you call MyView.Done, you need to  Dispose
  338. of  the  TCollection. If you don't check whether the  pointer  to
  339. TCollection  is  nil,  sometimes you will try to  dispose  a  nil
  340. pointer. Boom.
  341.  
  342. The only real protection is to be methodical about testing wheth-
  343. er pointers are set to nil before calling "Pointer^.procedure" or
  344. disposing pointers.
  345.  
  346. 4.A.  If  you  have a pointer in one object  to  another  object,
  347. assign  a valid value to this pointer in the Init constructor  if
  348. possible. (It isn't always possible/desirable.) If you leave  the
  349. pointer = nil in MyView.Init, you must later be perfect in  test-
  350. ing  whether the pointer is still nil. Turn RangeChecking on  for
  351. the first YEAR.
  352.  
  353. 4.B.  In your Done methods, ALWAYS check for a nil pointer before
  354. Disposing  objects you created but didn't insert into  the  view.
  355. Otherwise  you will find that a front panel Reset switch on  your
  356. computer is very important in the learning phase of Turbo Vision.
  357.  
  358. As  a  Pascal programmer you are just not used to  thinking  like
  359. this.  So save your source code to file BEFORE you run.  After  a
  360. while this diligence in assigning values to pointers and  testing
  361. for nil becomes automatic. Sounds like C, no?
  362.  
  363.  
  364.  
  365.  
  366.                                 6
  367.  
  368.  
  369.  
  370. 5. Pointer Safety in Construction
  371.        {note: a TGroup is a descendent of TView}
  372.         var
  373.           MyGroup : PView; {can point to any descendent of TView}
  374.         begin
  375.             .....
  376.             .....
  377.        >    MyGroup := New(PGroup, Init(.......));  <
  378.  
  379.          !!! ALWAYS do Construction as above !!!
  380.  
  381. Using the NEW function in the special way above combines allocat-
  382. ing the memory for a new object with calling its constructor Init
  383. to initialize the object and build its virtual method table.
  384.  
  385.   Yes there are other ways.
  386.               New(MyGroup, Init(.........));
  387.   Problem : Assuming you wanted a TGroup, you just constructed
  388.   and initialized a TView since MyGroup is of type TView. What-
  389.   ever type pointer MyGroup is will determine what type of object
  390.   you  will  construct. If the variable declarations are  not  on
  391.   screen, it is easy to forget what type MyGroup really is.
  392.  
  393.                MyGroup := New(PGroup);
  394.                MyGroup^.Init(........);
  395.   NEVER! if you forget to call .Init before you call a method of
  396.          MyGroup, could bomb - Reset switch time.
  397.  
  398.  
  399. Aside - There must be a way around all these pointers.
  400.   Now it has occurred to some of you (it did to me) that one  can
  401. avoid  some of the pointer experience when using  standalone  ob-
  402. jects by doing
  403.      var
  404.        MyObj : TView;  {TView is object, NOT a pointer type}
  405.  
  406. at  the  beginning  of a subroutine. The  subroutine  creates  an
  407. object  of type TView called MyObj and will dispose of it as  the
  408. subroutine ends.
  409.   This  works fine but you can still get caught if you forget  to
  410. call  MyObj.Init BEFORE you call ANY of the object's methods.  If
  411. Range checking is off and you call a virtual method, directly  or
  412. indirectly,  then  Boom. If Range checking is  on,  then  runtime
  413. error  if virtual method but no error if ordinary  method.
  414.   Still  your data fields have not been initialized  (happens  in
  415. Init)  and if they contain an object pointer, it won't be set  to
  416. nil. Your safety tests for nil pointers will fail - you could end
  417. up  disposing a pointer in your Done method that had  never  been
  418. assigned. Boom.
  419.  
  420.  
  421. Break
  422.  
  423.  
  424.  
  425.  
  426.  
  427.                                 7
  428.  
  429.  
  430.  
  431. Easy stuff
  432.  
  433. How about the ^Variable usage?
  434.  
  435. In Turbo Vision it is common to organize your variables (objects)
  436. by creating either a linked list of pointers to the variables or
  437. an array of pointers to the variables. This is convenient because
  438. it is also usual to create objects as the user needs them (like a
  439. File  Open  dialog  box) and then destroy them  to  regain  their
  440. memory.  If  all possible dialogs and other  objects  had  memory
  441. allocated  at program startup, it would be restrictive given  the
  442. large size of many of today's DOS programs.
  443.  
  444. So  the objects are scattered through memory (unlike an array  of
  445. objects which would be ordered) but their sizes don't all have to
  446. be the same (as for an array of a datatype). Same on disk  files.
  447. So back to pointers.
  448.  
  449. The ^Variable usage is much less common than the Pointer^  usage.
  450. This is simply because most object variables are already pointers
  451. in TV.
  452.  
  453.         APointer := ^AnyVariable;
  454.  
  455.   assigns the address of AnyVariable to APointer.
  456.  
  457.  
  458.   Also you see this all the time in type declarations:
  459.         type
  460.           PMyView = ^TMyView;
  461.  
  462.   Which declares PMyView to be a pointer to type TMyView.
  463.  
  464. Turbo Vision has alot of procedures that take pointers to strings
  465. as a parameter rather than the string itself. It goes against the
  466. Pascal grain but that's the way it is. So you will probably use a
  467. string  and  assign it a value in the usual way.  Then  pass  the
  468. string as a pointer to the procedure:
  469.          type
  470.            Str20 = string[20];                definition
  471.            PString = ^String;                 definition
  472.  
  473.            procedure DoIt(StrPtr : PString);  definition
  474.            begin
  475.            end;
  476.            ....
  477.  
  478.                 Str20  := 'AARDVARK';
  479.                 DoIt(Str20);    {type mismatch error}
  480.                 DoIt(^Str20);   {simple as that}
  481.  
  482.  
  483. If  you have stuck it out this far, congratulations.  Class  dis-
  484. missed.
  485. {-------------------------------}
  486.  
  487.  
  488.                                 8
  489.  
  490.  
  491.  
  492.  
  493. DESTRUCTING OBJECTS - Dispose versus Done
  494.  
  495. TV  documentation mentions that you should always call Done  when
  496. you are finished with an object. If the object is a TGroup,  then
  497. Done calls Done for all the subviews AND frees their memory.  But
  498. Done  does not free the memory used by the TGroup itself. If  you
  499. have  declared  the TGroup dynamically on the  heap  (New(PGroup,
  500. Init...)), then its memory is not freed/recovered.
  501.  
  502. Dispose(PMyObject,  Done)  both  calls the  Done  destructor  and
  503. frees/recovers the memory used by MyObject.
  504.  
  505. A simple rule is:
  506.  
  507.   Match each call to New(PMyObject,...)
  508.       with a call to Dispose(PMyObject, Done);
  509.  
  510. If you declare the object as a static variable
  511.     var  MyObject : TMyObject;  {not PMyObject}
  512. then just call Done. The compiler allocates and frees memory  for
  513. static variables.
  514.  
  515. A suggestion:
  516. It is easy to forget to recover memory. Take a copy of the  small
  517. demo  program  TinyDemo  and add the  HeapViewer  from  the  demo
  518. TVGDemo1. Then test your code using this program. The  HeapViewer
  519. will tell you immediately if you are losing memory.
  520.  
  521. {-------------------------------}
  522.  
  523. PSTRINGS and MEMORY OVERWRITES
  524.  
  525. TV  often  handles strings by using a pointer to them.  It  often
  526. organizes  groups  of  strings as Collections  of  PStrings.  For
  527. example it uses the following function to create PStrings:
  528.         function NewStr(S : string) : PString;
  529.  
  530. So      AStrPointer := NewStr('a string')
  531.   allocates memory for the string "a string" and returns a point-
  532. er to this memory. The amount of memory allocated is just  enough
  533. to  contain  the exact string you pass to the function  plus  one
  534. byte for the string's length. Very efficient memory usage.
  535.  
  536. This is fine until you want to change the contents of the string.
  537.  
  538. If you create a regular Pascal string
  539.  
  540.         MyString : string = 'Longer than a string';
  541.  
  542. and then assign MyString to the string pointed to by AStrPointer
  543.  
  544.        AStrPointer^ := MyString;
  545.  
  546. you Will OverWrite Memory not belonging to AStrPointer!  MyString
  547.  
  548.  
  549.                                 9
  550.  
  551.  
  552.  
  553. is too long to fit into the memory allocated for AStrPointer  but
  554. it  will be put there anyway. Notice that you have  no  foolproof
  555. way  to  know at run time how big the memory for  AStrPointer  is
  556. even though Pascal's memory manager knows. Hopefully Borland will
  557. come up with something better.
  558.  
  559. There are no error messages or compiler checks.
  560.  
  561. Note: if you want to assign AStrPointer^ a shorter string or  one
  562. of the same length, you should check first to see if  AStrPointer
  563. is nil. ( AStrPointer is set to nil if NewStr is passed an  empty
  564. string.)
  565.  
  566. >>  Think twice before changing the contents/length of  a  string
  567. pointer.
  568.  
  569. {-------------------------------}
  570.  
  571.  
  572. TV/TVGraphic ORDER OF VIEWS
  573.  
  574. The  Borland  doc never really gets around to nailing  down  view
  575. order.  We'll  try it here. TV refers to both  Turbo  Vision  and
  576. TVGraphic.
  577.  
  578. TGroup's  contain TViews. For the purposes of discussion here,  a
  579. TView is anything visible on the screen. TGroups are not  visible
  580. except for the Views they contain. The Application (TGroup)  con-
  581. tains  the  Menu, StatusLine and DeskTop.  The  DeskTop  (TGroup)
  582. contains a visible Background and the windows (TWindow - descends
  583. from TGroup) on screen. These windows contain TViews although  in
  584. TVGraphic  they  may also contain TSubWindows,  a  descendant  of
  585. TGroup. When thinking of view order, remember that every  visible
  586. part of TV is a TView.
  587.  
  588. There are two areas that depend on the order of views. One is the
  589. handling  of events and the other is the drawing of views on  the
  590. screen.
  591.  
  592. Terminology
  593.   Z- order : partially defined concept in Borland doc to explain
  594.              view order
  595.  
  596.   function TGroup.First
  597. Borland  = "returns a pointer to the TGroup's first subview,  the
  598. one closest to the top in Z-order."
  599.      The  FIRST subview gets passed keyboard and  command  events
  600. before  any  other subview. Visually it is the top  view  on  the
  601. screen  - all other views appear behind it. In Turbo Vision,  the
  602. First  subview draws first (counter-intuitive as that may  seem).
  603. In  TVGraphic, the First subview draws last. A subview newly  in-
  604. serted using TGroup.Insert becomes the First subview.
  605.  
  606.   function TView.NextView
  607. Returns  a pointer to the "Next" subview in the view's Owner.  So
  608.  
  609.  
  610.                                 10
  611.  
  612.  
  613.  
  614. if  you start with the First subview. You can chain  through  all
  615. the subview NextView pointers to reach the Last subview.
  616.   function TView.PrevView
  617. Returns  a pointer to the "Previous" view. So you could start  at
  618. the Last view and chain through all the PrevView subview pointers
  619. to the First view. Opposite direction from NextView.
  620.  
  621.   TGroup.Last   pointer field
  622. Points  to the Last subview in order. This view  receives  events
  623. last. Draws first in TVGraphic. Draws last in Turbo Vision.
  624.  
  625.   Top
  626. When discussing Z order, the First subview is at the top.
  627.  
  628.   Bottom
  629. When discussing Z order, the Last subview is at the bottom.
  630.  
  631.  
  632.  
  633. Note  that the subview list is circular. The TView.Next field  of
  634. the  Last  subview points at the First  subview.  The  TView.Prev
  635. function of the First subview returns a pointer to the Last  sub-
  636. view.
  637.  
  638. {----------------------------}
  639.  
  640. INSERTING VIEWS - Assumptions, Where, How
  641.  
  642. TV is based around certain assumptions about how you will  organ-
  643. ize your program. You don't have to follow these assumptions  but
  644. it sure makes life easier.
  645.  
  646. The first assumption is that you will insert all non-window views
  647. into a window or a descendant type of a window (dialog). Not into
  648. the DeskTop or Application.
  649.  
  650. The  second  assumption is that you will insert all  windows  and
  651. dialogs into the DeskTop. (InsertWindow and ExecuteDialog do this
  652. automatically for you).
  653.  
  654. The third assumption is that you will insert all objects  defined
  655. in unit Dialogs that are selectable or cause other objects to  be
  656. selected  (buttons, inputlines, listboxes, labels, etc.)  into  a
  657. dialog.
  658.  
  659. Well, what if you don't want to?
  660.  
  661. First Assumption
  662. In general, mixing selectable views with more than one window  in
  663. the desktop will interfere with moving between windows using  F6,
  664. Shift F6. See further discussion in section on TVGraphic's  TPan-
  665. Window in main doc file.
  666.  
  667. Also  inserting views outside the above assumptions will  usually
  668. cause  them  to draw in different colors since they  map  into  a
  669.  
  670.  
  671.                                 11
  672.  
  673.  
  674.  
  675. different  part  of the color palette. For  example.  a  dialog's
  676. palette  has many more entries than a TWindow, including  entries
  677. to  TButtons. In Turbo Vision, if you insert a button  into  your
  678. descendant  of  TWindow,  there are no  TWindow  palette  entries
  679. defined  for  it.  In TVGraphic, the window  palettes  have  been
  680. extended  so  the colors will be correct.  However  the  buttons'
  681. behavior will be different since a window and dialog HandleEvents
  682. differ.
  683.  
  684. Second Assumption
  685.           Note : Don't try to insert a dialog into a dialog.
  686. Modal  Dialogs: the only two sane choices are inserting  it  into
  687. the DeskTop (DeskTop.ExecView or TProgram.ExecuteDialog) or  into
  688. the Application. Use the DeskTop.
  689.  
  690. Non-modal dialogs (persistent dialogs}
  691. Insert into the DeskTop (DeskTop^.Insert). TVGraphic also  allows
  692. insertion of non-modal dialogs into a TPanWindow.
  693.  
  694. In General
  695. In  TVGraphic  (and perhaps Turbo Vision): If you insert  a  non-
  696. modal view into the Application rather than the DeskTop AND  this
  697. view overlaps the DeskTop, the redrawing mechanism will not  work
  698. properly.  It can't tell in what order this view should be  drawn
  699. relative to the DeskTop views.
  700.  
  701.  
  702. Third Assumption
  703. If  you want a button in your DeskTop, make it non-selectable  by
  704. clearing  its sfSelectable bit in its State field. If you want  a
  705. bank of selectable buttons, think about placing them in a special
  706. window. Then insert that window in the DeskTop. For other  dialog
  707. controls you are on your own. See discussion under First  Assump-
  708. tion.
  709.  
  710. {----------------------------}
  711.  
  712. DRAWVIEW vs DRAW
  713.  
  714. Even though Draw is the method that actually draws the view,  you
  715. should always call DrawView when you want a view to draw  itself.
  716. DrawView  checks if the view is Exposed and also resets the  text
  717. cursor if one exists.
  718.  
  719. {----------------------------}
  720.  
  721. COLOR PALETTES
  722.  
  723. TV's color palette system is the part of TV that this  programmer
  724. finds the most cryptic. There is a discussion on changing palette
  725. colors  in  the main doc file. Here we look at  concepts.
  726.  
  727. Note: It is often easier to avoid using the palette when  writing
  728. new Draw methods. Work back toward the palette method of  obtain-
  729. ing color as your application firms up.
  730.  
  731.  
  732.                                 12
  733.  
  734.  
  735.  
  736.  
  737. Each  type of view has what is called a color  palette.  Although
  738. palettes are  Pascal String types, it is best to think of them as
  739. arrays  of bytes. Only the TApplication has actual colors in  its
  740. palette.  All the other palettes contain numbers  that  represent
  741. offsets into the palette (array) of the view's Owner.
  742.  
  743. The application palette packs two four bit colors into each byte.
  744. Foreground  color  is the lower 4 bits, background is  the  upper
  745. four bits.
  746.  
  747. In  TV, the color a view will use to draw itself depends on  what
  748. type  of view it is inserted into. Example: the background  color
  749. of StaticText differs depending on whether it is inserted into  a
  750. window or a dialog. To make this happen, each view's Draw  method
  751. calls  the  view's GetColor function to find out what  colors  to
  752. use.  GetColor calls its Owner's GetColor recursively   until  it
  753. reaches the Application.
  754.  
  755. As  GetColor works it way up the view chain, it calls  GetPalette
  756. at  each level and sums the offset value from each palette  entry
  757. to get the total offset into the Application palette. (The  Desk-
  758. top  GetPalette  returns nil - it doesn't have a palette  so  the
  759. offset  values  GetColor has calculated are not  changed  by  the
  760. DeskTop.)
  761.  
  762. Pragmatically:
  763.  
  764. TV1.0 Dialogs:
  765.   The  offset  in the first palette entry is  32  (valid  entries
  766. range  from 1 up). So anything inserted into a TDialog will  have
  767. the offsets in its own palette increased by 31.
  768.   (A  subview  palette offset of 1 will map to the  first  dialog
  769. palette entry of 32. So 32-1 = 31.)
  770.  
  771. TV2.0 default "Cyan" Dialog
  772.   The offset of the first palette entry is 96. Anything  inserted
  773. into  a Cyan dialog will have the offsets of its own palette  in-
  774. creased by 91.
  775.  
  776. For a "BlueWindow"
  777.   The offset in the first palette entry is 8. So anything insert-
  778. ed  into  a  "BlueWindow" (light gray  with  blue  highlights  in
  779. TVGraphic) will have the offsets in its own palette increased  by
  780. 7.
  781.  
  782. If you insert a window in a window for example, then entries will
  783. be  increased  by 7 by each window's  GetPalette.   The  inserted
  784. window no longer maps to the expected colors. TVGraphic's TSubwin-
  785. dow  avoids this problem by using a modified GetPalette  function
  786. which  senses  when  the subwindow's Owner is also  a  window  or
  787. descendant of TWindow.
  788.  
  789. TVGraphic handles the insertion of dialogs in a window by extend-
  790. ing the window palette.
  791.  
  792.  
  793.                                 13
  794.  
  795.  
  796.  
  797.  
  798.  
  799. Example:
  800.   TInputLine inserted into the usual Cyan Dialog
  801.     The  second entry in the TInputLine palette is  for  "Active"
  802.     text.  (Active means the window  TInputLine is inserted  into
  803.     is in the Active state.)
  804.       The offset of the second entry is 19.
  805.     Draw obtains the active colors by calling GetColor(2).
  806.         (2 for second entry in TInputLine's palette)
  807.     To calculate the offset into the application's Palette,
  808.       add 91 (from cyan Dialog) to 19 = 110. The colors GetColor
  809.       returns are from the 110th entry in TApplication's palette.
  810.  
  811.  
  812. {----------------------------}
  813.  
  814. COMMUNICATION AMONG VIEWS IN A DIALOG BOX (TDIALOG)
  815.  
  816.   Many  View  types  can be included in a Dialog box  and  it  is
  817. helpful to consider the interview communication that takes place.
  818. The summary below is true for TVGraphic and is generally true for
  819. TV.
  820.  
  821.   Remember - all predefined Dialog boxes in TV are ExecView'd  by
  822. the Desktop rather than Inserted - this makes them "modal".  This
  823. means that the Dialog box fetches all Events from the Event queue
  824. rather  than  the Application fetching them.  So  Event  handling
  825. begins in TDialog.HandleEvent.
  826.  
  827.   Note that when a Dialog box is modal, there is no real  differ-
  828. ence  in a subView using the Message function to call  its  Owner
  829. and  sending a PutEvent - both events end up in  TDialog.HandleE-
  830. vent.  (Of course a Message is processed immediately, a  PutEvent
  831. goes to the rear of the Event queue.) Often the event is of  type
  832. evBroadcast so it will reach all the Dialog's views in case  more
  833. than one needs to react.
  834.   BUT  if a Dialog box is Not Modal, an event sent with  PutEvent
  835. would  first  show up at TProgram.HandleEvent. If it was  an  ev-
  836. Broadcast, it would be received by EVERY view in the application!
  837.  
  838.   Note  that  EndModal returns the  terminating  command  through
  839. ExecView or ExecuteDialog.
  840.  
  841.   Summary of commands and messages:
  842.  
  843.   TDialog.HandleEvent(Event)
  844.     if AllowBothMButtons is false (TVGraphic default) then
  845.       right mouse click generates a PutEvent with
  846.             Event.What := evCommand
  847.             Event.Command := cmCancel
  848.             Event.InfoPtr := nil
  849.     call TWindow.HandleEvent, return
  850.     keystrokes:
  851.       kbEsc:   PutEvent   evCommand,cmCancel,InfoPtr := nil;
  852.  
  853.  
  854.                                 14
  855.  
  856.  
  857.  
  858.       kbEnter: PutEvent   evBroadcast,cmDefault,InfoPtr := nil;
  859.     evCommand:
  860.       case Event.Command of
  861.         cmOk, cmCancel, cmYes, cmNo:
  862.           if State and sfModal <> 0        {if TDialog is modal}
  863.                   EndModal(Event.Command);
  864.              {next part is TVGraphic only}
  865.         else if (VOptions and ReturnOnAnyButton <> 0)
  866.           and (State and SfModal <> 0)
  867.               EndModal(Event.Command);
  868.       end;
  869.  
  870.  
  871.   TButton
  872.    Note: TVGraphic handles the Default button differently from TV
  873.           TV buttons send messages using commands
  874.               cmGrabDefault, cmReleaseDefault.
  875.           TVGraphic does not use these messages or commands.
  876.     .HandleEvent
  877.           various situations call Press
  878.     .Press
  879.       Message      Owner,evBroadcast,cmRecordHistory,InfoPtr=nil
  880.       if bfBroadcast set
  881.         Message    Owner,evBroadcast,buttoncommand,InfoPtr= @Self
  882.       bfBroadcast not set
  883.         PutEvent   evCommand,buttoncommand,InfoPtr := @Self
  884.  
  885.  
  886.   TFrame
  887.     CloseButton:   if window has a pulldown menu, activate menu
  888.        and PutEvent the selected menu command,
  889.        otherwise   PutEvent   evCommand,cmClose,InfoPtr := Owner
  890.     ZoomButton:    PutEvent   evCommand,cmZoom,InfoPtr := Owner
  891.     NextWindowBut: PutEvent   evCommand,cmNext,InfoPtr := Owner
  892.  
  893.  
  894.   TScrollBar
  895.     .HandleEvent  for evMouseDown or recognized evKeyDown, calls
  896.        Clicked (local procedure, not a method)
  897.          Message
  898.              Owner,evBroadcast,cmScrollBarClicked,InfoPtr=@Self
  899.     .SetParams calls
  900.       .ScrollDraw
  901.          Message
  902.              Owner,evBroadcast,cmScrollBarChanged,InfoPtr=@Self
  903.  
  904.  
  905.   TListViewer, TListBox
  906.     .HandleEvent
  907.       evBroadcast
  908.         cmScrollBarClicked
  909.           if command is from its own scrollbar
  910.             (checks InfoPtr versus HScrollBar,VScrollBar)
  911.           then calls TView.Select {ListViewer selects itself}
  912.         cmScrollBarChanged
  913.  
  914.  
  915.                                 15
  916.  
  917.  
  918.  
  919.           if command is from its own scrollbar:
  920.             if from vertical scroll bar
  921.                 then .FocusItemNum(VScrollBar^.Value)
  922.             sets flag for later redaw of self {TVGraphic}
  923.  
  924.     .ChangeBounds calls TScrollBar.SetStep DIRECTLY
  925.         SetStep then calls TScrollBar.SetParams
  926.     .SetRange     calls TScrollBar.SetParams DIRECTLY
  927.  
  928.  
  929.   TInputLine,TgInputLine
  930.     does not communicate with other views.
  931.     Note that descendent TFileInputLine receives update commands
  932.       from a TFileListBox.
  933.  
  934.  
  935.   TLabel,TgLabel
  936.     Link : PView    selectable view that label is linked to.
  937.     .HandleEvent
  938.       If mouse clicks on label or hot key is pressed, calls
  939.       Link^.Select which causes linked view to select itself -
  940.       to become the selected view in the dialog.
  941.  
  942.       if Event.What = evBroadcast then
  943.         if (Event.Command = cmReceivedFocus) or
  944.          (Event.Command = cmReleasedFocus) then
  945.       Label sets its Light field true if its linked view  is
  946.         the focused view. Then redraws itself.
  947.         Label colors differ when Light is true.
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.                                 16
  977.