Turbo Pascal menus

 .PO 0

.PL 66

   WINDOWS AND MENUS, FOR TURBO PASCAL

      ------------------------------------------------------------------------

       REFERENCE GUIDE




   VERSION 1.5

   BY G.R.DYKE

       (c)1991

.PA 

Š      TABLE OF CONTENTS


      DESCRIPTION OF TOPIC                                             PAGE NO

      ------------------------------------------------------------------------


      PART 1: PROGRAMMER'S REFERENCE...................................... 7

      ------------------------------


      INTRODUCTION........................................................ 8

      What's on Your Discs................................................ 8

Installing Windows and Menus on Your System..................... 10

      About This Manual.................................................. 10

      How to Contact us.................................................. 10


      CHAPTER 1: THE WINDOWS AND MENUS UNIT, WINMEN.TPU.................. 11

      Unit Dependantcies................................................. 11

      Winmen declared types (Additional to Turbo Pascal Types)........... 11

B1_4, B0_15, B1_23.............................................. 13

B1_24, B1_25, B1_78............................................. 13

B1_80, B2_25, B3_25, B3_80...................................... 13

W0_400.......................................................... 13

mtext........................................................... 13

mmenu........................................................... 13

Colour Chart.................................................... 15

Ascii Chart..................................................... 15

screen.......................................................... 16

wmrec........................................................... 17

    Fields used by windows, menus & user screens only............ 17

       .typ...................................................... 17

       .op_cl.................................................... 18

       .l, .r, .t, .b............................................ 18

       .tb, .tf.................................................. 18

       .horc..................................................... 18

    Fields used by windows & menus only.......................... 19

       .bar...................................................... 19

       .bb, .bf.................................................. 19

       .tlc, .trc, .blc, .brc.................................... 19

    Fields used by menus only.................................... 19

       .comnt.................................................... 19

       .tbc, .tfc................................................ 19

       .pc....................................................... 20

       .nrow, .ncol.............................................. 20

       .sumopt................................................... 21

       .row...................................................... 21

       .bar_start, .bar_end...................................... 21

       .first.................................................... 21

    Fields used by pop & list menus only......................... 22

       .trow..................................................... 22

       .rows_vis................................................. 22

    Fields used by bar menus only................................ 22

       .ncolc.................................................... 22

       .gap...................................................... 22

       .cols_vis................................................. 23

.PA 

Š     Fields used by windows only.................................. 23

       .x, .y.................................................... 23

       .lt, .rt, .tt, .bt........................................ 23

       .max...................................................... 23

       .cp....................................................... 23

maprec.......................................................... 24

    .ID.......................................................... 25

    .sc_inx...................................................... 25

    .next........................................................ 25

pt_maprec....................................................... 24

pt_mtext........................................................ 30

pt_mmenu........................................................ 30

pt_wmrec........................................................ 30

pt_scr.......................................................... 31

      Winmen declared Global Variables 

(Additional to Turbo Pascal Variables).......................... 31

wt.............................................................. 31

VIDEO........................................................... 31

scr............................................................. 32

log............................................................. 32

comment......................................................... 32

IDG............................................................. 32

MENU_EXIT_BY_CURSOR............................................. 32

MENU_ACT_ON_PC.................................................. 33

CLOSE_WITH_REMOVE............................................... 33

IDW_active, IDM_active.......................................... 34

gdriver, gmode.................................................. 34

ID_WM[]......................................................... 35

ID_MM[]......................................................... 35

ID_SC[]......................................................... 35

ID_MC[]......................................................... 35

MAP[]........................................................... 25

      Winmen Initialisation.............................................. 37

      Winmen Quick Reference Lookup...................................... 38

Windows Functions High Level.................................... 38

Windows Procedures High Level................................... 38

Windows Procedures Low Level.................................... 38

Menus Functions High Level...................................... 38

Menus Procedures High Level..................................... 39

Menus Procedures Low Level...................................... 39

Common Functions Low Level...................................... 40

Common Procedures High Level.................................... 40

Common Procedures Low Level..................................... 41


      CHAPTER 2: THE WINDOWS AND MENUS COMPLETE REFERENCE LOOKUP......... 42

      Sample Procedure................................................... 42

      Windows Functions.................................................. 44

new_win()....................................................... 45

      Windows Procedures................................................. 48

wclrscr()....................................................... 49

wcolour()....................................................... 51

wexplode()...................................................... 53

wgotoxy()....................................................... 55

wopen()......................................................... 57

wselect()....................................................... 59

Š wwrite()........................................................ 61

wwriteln()...................................................... 64

_wbox_on()...................................................... 67

_wchk_min_size()................................................ 71

_wscroll_up()................................................... 73

      Menus Functions.................................................... 76

bar_menu()...................................................... 77

list_menu()..................................................... 81

new_menu()...................................................... 85

pop_menu()...................................................... 90

      Menus Procedures................................................... 94

mbar_comment().................................................. 95

mchange_char().................................................. 98

mpic_col()..................................................... 101

_mbbar_end()................................................... 103

_mbbar_home().................................................. 105

_mbbar_left().................................................. 107

_mbbar_off()................................................... 109

_mbbar_on().................................................... 111

_mbbar_right()................................................. 113

_mbdisplay()................................................... 115

_mchk_on_screen().............................................. 118

_mdisplay().................................................... 120

_mlbar_blst().................................................. 122

_mlbar_end()................................................... 124

_mlbar_home().................................................. 126

_mlbar_tlst().................................................. 128

_mlmov_do().................................................... 130

_mlmov_up().................................................... 134

_mpbar_end()................................................... 136

_mpbar_home().................................................. 138

_mplbar_do()................................................... 140

_mplbar_off().................................................. 142

_mplbar_on()................................................... 144

_mplbar_up()................................................... 146

      Commoî Functions.................................................® 148

_wmchk_for_mrec().............................................. 149

_wmsave_scr().................................................. 151

      Common Procedures................................................. 153

wmadd_mrec_all()............................................... 154

wmattribs().................................................... 157

wmclose()...................................................... 160

wmdelete()..................................................... 162

wmdel_mrec_all()............................................... 165

wmfloat()...................................................... 168

wmmem_stat()................................................... 171

wmmove()....................................................... 183

wmremove()..................................................... 186

wmrest_scr()................................................... 189

wmsave_scr()................................................... 192

wmslide()...................................................... 204

wmtitle()...................................................... 211

.PA 

Š _wmadd_mrec().................................................. 217

_wmbox_attribs()............................................... 219

_wmchk_exist()................................................. 223

_wmchk_mem()................................................... 225

_wmchk_type().................................................. 228

_wmcopy_scr().................................................. 230

_wmdel_mrec().................................................. 232

_wmrest_scr().................................................. 234

_wmslide_d()................................................... 236

_wmslide_l()................................................... 240

_wmslide_r()................................................... 243

_wmslide_u()................................................... 246

 

      PART 2: APPENDICIES............................................... 249

      -------------------


      APPENDIX A: ERROR MESSAGES........................................ 250

      Windows Error Messages............................................ 250

      Menus Error Messages.............................................. 251

      Common Error Messages............................................. 251

.PA 

Š





                      THIS PAGE LEFT INTENTIONALLY BLANK






.PA

Š       P                      A                       R                      T 

      ------------------------------------------------------------------------

     1






      PROGRAMMER'S REFERENCE

.PA 

Š      I      N      T      R      O      D     U     C     T     I     O     N

      ------------------------------------------------------------------------


      Welcome to Windows and Menus for Turbo Pascal, a complete library of

      powerfull functions and procedures packed into one Turbo Pascal Unit

      Winmen.Tpu, in fact 67 in all, each one designed to make the programmers

      life a little easier and his or her applications just that little bit

      more professional looking, not to mention functional and flexible.

      Windows and Menus makes creating, good looking, practical programmes

      a joy rather than a chore and of course the end result, which is what

      we all want, comes up in a fraction of the time that would be required

      to produce the same application programme without the use of Windows and

      Menus. One other very important aspect of using the Windows and menus

      Unit, which may not have occured to everyone, is that the actual source

      code, which you write, becomes automatically more manageable, because

      you do not have to worry about any of the code associated with any of

      the Windows and Menus functions and procedures, its all taken care of

      in the Unit, so for example, if the code for one of the Windows and

      Menus routines is changed, all the user would have to do, on recipt of

      an update, would be recompile all the modules of his code that used that

      particular function or procedure, rather than having to change reams

      and reams of code in dozens of modules. These benefits are of course

      automatic to all users of Turbo Pascal Units and are synonimus with the

      modular approach to programming and not just common to the Windows and

      Menus Unit.


      What's On Your Discs

      ------------------------------------------------------------------------


      Windows and Menus comes on two 5.25, or one 3.5 inch distribution

      disc(s). For 5.25" disc users:-

Disc 1 contains all the example programmes from the manual, two

      demonstration programmes, one application programme, all with source and

      object code and the Windows and Menus Reference Guide.

Disc 2 containes the Windows and Menus interface section and the

      actual TP Unit file.

All files have been archived using the LHARC.EXE utility, which

      is also on disc 1, to enable us to pack them onto as few disc's as

      possible, see the LHARC.DOC file, or just type LHARC at the prompt for

      info on how to use this very simple programme.

Below is a complete listing of all the files contained on disc and in

      the archive .LZH files, so you can choose which ones to load on to your

      system, you will probably only need the WINMEN.TPU (library) file, about

      1,100,000 bytes will be required to unarchive all the files.


      README       To see any last-minute notes and corrections, Type README

      (If Present) at the system prompt. (If you have a printer you can print

   it out.) Once you have reviewed this material keep it 

   around for future reference.


      EXAMPLES.LZH These are all the example programmes exactly as you will

      *.PAS Files  find them in the Windows and Menus Reference Guide, to

   save you hours of typing and they have all been tested

   fully, so there should'nt be any frustrating moments.


Š      DEMOS.LZH    This is the Windows and Menus basic demonstration programme,

      WINDEMO.EXE  to give you a taste of what can be done using this units,

   basic features, available in V1.0 and V1.5.


      DEMOS.LZH    Here's the source code for the above demonstration, so

      WINDEMO.PAS  you can see how it's been done.


      DEMOS.LZH    This is the Windows and menus advanced demonstration

      ADVANCED.EXE programme and covers all of the units more advanced

   features, available from V1.5 onwards.


      DEMOS.LZH    Here's the source code for the above demonstration, so

      ADVANCED.PAS you can see how it's been done.


      DEMOS.LZH    This is a fully working application programme, that makes

      PAGEPRNT.EXE full use of the Winmen unit, to prove what is demonstrated

   in the above demo programmes.

      It is a fully featured Epson/IBM compatible printer set

   up utility, complete with print spooler facility, it

   should work fine with most printers. Not only does it

   show off the Winmen unit, but also many advanced features

   of Turbo Pascal as well.

      The main purpose of including this programme and its

   source code, is to demonstrate exactly how to get a list

   of dos filenames into a Winmen Menu, using a filename

   template, which can include the wild cards '?' and '*' or

   just single filenames. It also demonstrates how to use

   them once you have got them into the Menu.

      There is no manual supplied, as we don't think you

   will require one, it is very easy to use, just experiment.


      DEMOS.LZH    Here's the source code for the above application, so you

      PAGEPRNT.*   can see how it's been done.


      MANUAL.LZH   This is the complete Windows and Menus Programmers

      WINMEN.DOC   Reference Guide, on a disc, ready for you to print out,

   you will need about 260 pages of paper. It is a plain

   ascii file so should be compatible with all editors and

   page break numbers have been put in to give you a guide.

      If you specifically want a Wordstar format version, to

   save you the nightmare of editing the ascii file version,

   which also contains all the appropriate embolden control

   characters etc, then we would be more than happy to supply

   you with one, just sent a blank disc, size of your choice,

   along with your name, address, and postcode to the address

   supplieä oî pagå 1° oæ thió manual® Pleaså alsï includå one

   pound for postage and packing, checks payable to G.R.Dyke,

   please allow a couple of weeks for delivery.

      Alternatively see the order form at the end of the

   WINDEMO.EXE demonstration programme.


      WINMEN.PAS   This is the complete interface section listing from the

   Windows and Menus Unit, with nothing missing at all, so

   that you can inspect all the new variable types, the

   actual global variables defined for the unit, both of

Š    which of course become available to the user whenever the

   WINMEN.TPU unit is used in one of your programmes and

   lastly the initialisation section, so you can see what

   certain global variables are initialised to, each time an

   application programme, that uses WINMEN.TPU, is run.


      WINMEN.TPU   This is Windows and Menus unit library and contains all

   the code for every function and procedure in the unit.

   This is probably the only file you will need to copy on

   to your system disc.


      Installing Windows And Menus On Your System Disc.

      ------------------------------------------------------------------------


      This is the easy part, simply copy the WINMEN.TPU library file onto your

      system, into the subdirectory that contains all the other .TPU files,

      this will ususly be called EXE or UNIT, if in doubt copy it into each.

      This file must be accessable to the compiler at compile time.


      About This Manual

      ------------------------------------------------------------------------

      This manual is split into two parts: a programmers reference section and

      appendices. The first part of this manual, "The Programmers Reference"

      offers technical information on the following subjects:


      >Chapter 1: The Windows and Menus unit, WINMEN.TPU


      >Chapter 2: The Windows and Menus complete reference lookup


      Part 2 of this manual "Appendices" contains listings of all runtime

      error messages that could be generated by the Windows and Menus code


      >Appendix A: Windows Error Messages

   Menus Error Messages

   Common Error Messages


      How To Contact Us

      ------------------------------------------------------------------------


      If, after reading this manual and using Windows and Menus, you would

      like to contact us with comments, suggestions or a technical querie,

      we suggest that you write a letter detailing your problem and send it

      to:-


      G.R.Dyke,               Also include the following:-

      8, Middle Road,         >Product name and version number.

      North Baddesley,        >Product serial number.

      Southampton.            >Computer make and model number.

      Hants SO52 9JE.         >Operating system and version number.

      England.


      Unfortunatly we cannot offer any telephone support at this time.


.PA 

Š      C           H           A           P           T           E          R

      ------------------------------------------------------------------------

     1





      THE WINDOWS AND MENUS UNIT, WINMEN.TPU



      Units are the basis of modular programming in Turbo Pascal. They are

      used to create libraries that you can include in various programmes

      without making the source code available, and to devide large programmes

      into logically related modules.


      UNIT-->INTERFACE PART-->IMPLEMENTATION PART-->INITIALIZATION PART


      Further information on units in general can be obtained from the 

      Turbo Pascal Reference Guide.


      Unit Dependantcies

      ------------------------------------------------------------------------


      The Windows and Menus unit is dependant upon the following Turbo Pascal

      standard units:- Crt, Dos and Graph, These three units are called in the

      Uses clause of the Winmen unit, so any programme or unit that uses the

      Windows and Menus unit "Winmen" in its Uses clause need not include the

      Crt, Dos or Graph units in that clause as they are already called.

      None of the routines in the Winmen unit are defined by standard pascal

      thus they are placed in there own unit.


      Winmen Declared Types, (Additional To Turbo Pascal Types)

      ------------------------------------------------------------------------

 

      Each of the types defined by the Winmen unit are briefly discussed in

      this section. For more detailed information, see the descriptions of the

      functions and procedures that depend on these objects in Chapter 2 "The

      Windows And Menus Complete Reference Lookup". Where this is not

      applicable, a full description is given in this section.


      type                     {*ALL BYTE SETS BETWEEN THE VALUES SHOWN*}

B1_4    = 1..4;       {*WINDOW/MENU BORDER BOX TYPE*}

B0_15   = 0..15;      {*ALL BACKGROUND & FOREGROUND COLOUR VALUES*}

B1_23   = 1..23;      {*>                                     <*}

B1_24   = 1..24;      {* >                                   < *}

B1_25   = 1..25;      {*  >                                 <  *}

B1_78   = 1..78;      {*   > ALL MENU/WINDOW LIMITS VALUES <   *}

B1_80   = 1..80;      {*   >                               <   *}

B2_25   = 2..25;      {*  >                                 <  *}

B3_25   = 3..25;      {* >                                   < *}

B3_80   = 3..80;      {*>                                     <*}

W0_400  = 0..400;     {*WORD VAL SENT TO NEW_MENU() & RETURNED FROM*}

       {*LIST_MENU() (MENU OPTIONS)                 *}

.PA 

Š mtext  = array[1..400] of string[80]; {*USER MENU OPTION TEXT ARRAY*}

mmenu  = array[0..402,0..80] of word; {*MENUS SCREEN RAM FORMAT OF*}

       {*MTEXT                     *}

screen = array[0..2000] of word;      {*SAVED SCREEN AREA BEHIND*}

       {*WINDOW OR MENU IN SCREEN*}

       {*RAM FORMAT              *}


wmrec = record               {*WINDOW/MENU/USER SCREEN, RECORD*}

    typ : char;               {*RECORD TYPE I.E. WINDOW OR MENU*}

    op_cl : boolean;          {*FLAG FOR 1=OPEN/0=CLOSED*}

    bar   : boolean;          {*FLAG FOR A MENU OPEN AS A BAR MENU*}

    comnt : boolean;          {*FLAG 1=BAR MENU COMMENTS 0=NONE*}

    first : boolean;          {*FLAG 1=MENU NEVER OPENED, 0=OPENED*}

    x,y : byte;               {*X,Y CURSOR POSITION IN A WINDOW ONLY*}

    l : B1_80;                {*>                            <*}

    r : B1_80;                {* >CURRENT BOUNDS OF A WINDOW< *}

    t : B1_25;                {* >MENU OR USER SCREEN AREA  < *}

    b : B1_25;                {*>                            <*}

    lt,rt   : B1_80;          {*WINDOW TEMPARARY LEFT,RIGHT BOUNDS*}

    tt,bt   : B1_25;          {*WINDOW TEMPARARY TOP,BOTTOM BOUNDS*}

    max     : B1_80;          {*WINDOW MAXIMUM OF (R-L) & (B-T)*}

    bb,bf   : B0_15;          {*WIN/MEN BORDER BACK & FORE COLOURS*}

    tb,tf   : B0_15;          {*WIN/MEN TEXT BACK & FORE COLOURS*}

    tbc,tfc : B0_15;          {*MENU COMPLEMENT OF TEXT COLOURS*}

    pc      : B0_15;          {*MENU FIRST (PICK) CHAR COLOUR*}

    nrow     : word;          {*TOTAL NUMBER OF ROWS IN WIN/MEN*}

    ncol     : word;          {*TOTAL NUMBER OF COLUMNS IN WIN/MEN*}

    ncolc    : byte;          {*NUMBER COLS OF COMNT IN BAR OPTION*}

    sumopt   : word;          {*SUM OF ALL THE BAR MENU OPTION TXT*}

    gap      : B1_80;         {*GAP SIZE BETWEEN BAR MENU OPTIONS*}

    row,trow : word;          {*CURRENT & TOP ROW OF LIST/POP MENU*}

    rows_vis : B1_23;         {*ACTUAL ROWS VISIBLE LIST/POP MENU*}

    cols_vis : word;          {*ACTUAL COLUMNS VISIBLE-BAR MENU*}

    tlc,trc,blc,brc   : word; {*WIN/MEN CORNERS IN SCR RAM FORMAT*}

    horc,verc         : word; {*WIN/MEN EDGES IN SCREEN RAM FORMAT*}

    cp                : word; {*CENTRE POINT OF WIN SCR RAM FORMAT*}

    bar_start,bar_end : word; {*MENU BAR START & END SCRN ADDRESS*}

end;


pt_mtext  = ^mtext;          {*POINTER TO USERS MENU TEXT ARRAYS*}

pt_mmenu  = ^mmenu;          {*POINTER TO SCR RAM FORMAT OF ABOVE*}

pt_wmrec  = ^wmrec;          {*POINTER TO WIN/MEN/SCR RECORD*}

pt_scr    = ^screen;         {*POINTER TO SAVED SCREEN AREA ARRAY*}

pt_maprec = ^maprec;         {*POINTER TO 3D SCREEN MAP RECORD*}


maprec = record              {*3D SCREEN MAP RECORD*}

    ID : byte;                {*ID OF OBJECT THAT OWNS THIS MAPREC*}

    sc_inx : word;            {*ID_SC[] INDEX FOR OBJECTS BACKGROUND*}

    next : pt_maprec;         {*POINTER TO NEXT MAPREC IN LINKED LST*}

end;

.PA 

Š      >>B1_4, B0_15, B1_23, B1_24, B1_25,

      B1_78, B1_80, B2_25, B3_25, B3_80 = byte;

      These types are all defined to be values of type byte, between the

      ranges shown, ie. B1_23 would give a byte type variable with an

      allowable range of 1 to 23, anything outside this range would of

      course produce a range check error (provided the {$R+} compiler

      directive is set).

B1_4  is used for the window and menu border box type.

B0_15 is used for all the window/menu background and foreground

       text colours.

The remainder of types in this group are used for all window

menu and user saved screen limits, ie. left top right and bottom.


      >>W0_400 = word;

      This is a word type, which is used in the unit to define variables, to 

      send values to, and receive from, functions and procedures, namely the 

      number of options in a menu for NEW_MENU(), and the number of the option

      chosen on a menu for POP_MENU(), LIST_MENU() and BAR_MENU().


      >>mtext = array[1..400] of string[80];

      This string type defines an array of 400 strings of length 80, this is  

      designed to make it easier, and when used in conjunction with a pointer

      to this type (pt_mtext, see below), more memory efficient, for the user 

      when he/she is defining text strings for all menus and bar menu comment 

      strings for bar menus, although you can of course define your own 

      similar type if you wish. For full details of this type and how to use 

      it to best effect see the NEW_MENU() and MBAR_COMMENT() sections in the 

      Complete Reference Lookup.


      >>mmenu = array[0..402,0..80] of word;

      This word type will be explained in more detail here as it is not

      actually used, directly, as a parameter for any of the Windows or Menus

      functions and procedures, but is a very important basic building block

      for all menus.

Firstly the type defines a 2D word array of 402x80 words, that is each 

      element in the 402 array has access to 80 words. Now by coincidence the

      screen is 80 Ascii characters wide, But you say, the array is 80 words,

      correct, although the screen is 80 characters wide, that is in Ascii 

      terms, or how it actualy appears to the user, in reality each screen

      cell or character in screen ram is one word, hense the 80 words for

      each of the 402 array elements will give us enough memory to hold one 

      screen line for each one, giving us a possible maximum of 402 screen

      lines. 

Each screen ram character word is organised as described below:-

      CHARACTER BYTE, COLOUR BYTE (but DOS requires the low byte first!).

      LOW BYTE FIRST : COLOUR BYTE, HIGH BYTE LAST : CHARACTER BYTE.

.PA 

Š





                          PAGE 14 TO BE PRINTED HERE






.PA 

Š





                          PAGE 15 TO BE PRINTED HERE






.PA

Š      Where ID is the reference byte returned from NEW_MENU() when the menu

      in question was set up, and ID_MM[] is the array of pointers, mentioned

      above, each one of which could point to a separarte mmenu structure.

      This assignment gives the IDM pointer the starting address for the above

      menu structure.

You could of course not bother with defining the IDM pointer and just

      use the array of pointers to reference the above menu, like this:-

      ID_MM[ID]^[4][0..15], this is equivalent to IDM^[4][0..15], but I think

      it's neater to define the pointer. 

The [0..15] range is only there to indicate the width of the above 

      menu, you would only normaly use one number for the index thus:- 

      IDM^[4][1], this would access word 1 in line 4 of the above menu, which 

      is the word describing the character 'O'.

You will see all the above techniques used from time to time in the

      example programmes supplied with the Windows and Menus unit, it is a

      very important aspect of the unit and the descriptions here, of all the

      new types and variables, will enable you to extract the most benefit

      from it, but it will require a little studying.


      >>screen : array[0..2000] of word;

      This is another array of type word, this time it is just a single

      array[0..2000] of word, this type gives us sufficient space to save

      all 25 screen lines, of 80 characters into, in other words we may

      save a complete screen full of information into this array type.

Each word represents a character in screen ram format exactly as

      above in the mmenu array.

The purpose of a structure of this type is to save, or copy into it

      all the screen ram data beneath a window or menu before it is opened

      so that it can be copied back to screen ram when the window or menu

      is finished with, effectively closing it.

As with the mmenu and mtext arrays the Windows and Menus unit never

      actualy defines a variable of this type directly, but does so by means

      of pointers, all the pointers being of type pt_screen (see pt_screen

      below) which are held in a pointer array called ID_SC (see ID_SC

      below). This time when the unit uses getmem() to allocate memory for

      the structure, of type screen[0..2000], it only needs to reserve

      exactly enough for the actual size of the window or menu, that is

      Length x Width, unlike the mmenu and mtext type structures above,

      which needed to allocate all 80 words width x length, regardless of

      the actual width of the menu, this is because the screen data only

      needs to be saved into the screen array in a linear fashion, the

      number of rows and columns variables, from the wmrec (see wmrec below)

      are used to calculate how to copy the data back to screen ram from

      the linear screen array when the window or menu is closed.

To access a screen array for a particular window or menu, assuming

      it has already been set up using NEW_WIN() or NEW_MENU(), you would

      need to do the following:-

      var

IDS : pt_screen; (see pt_screen below)

      This defines the pointer variable that you need to point to the screen

      array, next you need to give the nil pointer a valid address to point

.PA

Š      to, ie. the start address for that particulr windows or menus screen

      array data, like this:-

      IDS := ID_SC[ID]; (see ID_SC below)

      Where ID is the byte value reference for the window or menu in question

      as returned from NEW_WIN() or NEW_MENU(), as explained in mmenu above.

      Then to access the screen array data an assignment like this would be

      used:- some_word_var := IDS^[index]; or IDS^[index] := some_word_var;

      Again as for mmenu you could just use the predefined pointer array

      ID_SC[] to access the relevant screen array for that particular window


      >>wmrec = record;

      This is the main Windows and Menus unit record structure, every window

      menu or user saved screen that has been created with NEW_WIN(), 

      NEW_MENU() or WMSAVE_SCR() will have one of these records, but which

      fields are filled in depends on weather the object is a window, menu or

      a user saved screen, this is given below.

As for mmenu and screen, wmrec is always used in conjunction with a

      pointer of type pt_wmrec (see pt_wmrec below), and again all the

      pointers are stored in a pointer array ID_WM[] (see ID_WM[] below), so

      the procedure for accessing a particular record structure, assuming

      that the window, menu or user saved screen has already been set up 

      using either NEW_WIN(), NEW_MENU() or WMSAVE_SCR(), is as follows:-


      var

IDR : pt_wmrec; (see pt_wmrec below);

      This defines our pointer to a record structure of type wmrec, next we

      need to give the nil pointer an address to point to, this will be the

      base address for that particular record structure:-

      IDR := ID_WM[ID]

      The above assignment gives the pointer the address of that record

      whoose reference is ID, where ID is the byte value returned from the

      NEW_WIN() or NEW_MENU() functions or the user saved screen number

      sent to WMSAVE_SCR(). Once this has been done you an access  all the

      individual record fields in the normal way:- IDR^.rec_var, where 

      rec_var is any of the record fields, as described below.

You could of course access the record in question without defining

      a pointer, using just the predefined pointer array:- ID_WM[ID]^.rec_var;

      although this is not as tidy as defining a pointer it is equivalent to

      it.


      N.B: A window, menu or user saved screen is refered to below as the

   'object' for convienience only.

      

      Fields Used By Windows, Menus and User Saved Screens:-

>>.typ : char;

This field describes the object, and will be 'W' for Window and user

saved screen or 'M' for a menu. This is defined when either NEW_WIN()

NEW_MENU() or WMSAVE_SCR() is called.

.PA

Š >>.op_cl : boolean;

This is a flag which sayes weather the object is open or closed and

will be true for open and false for closed. This is set true when

the window is opened using WOPEN(), when the menu is activated with

POP_MENU(), LIST_MENU() or BAR_MENU() and for a user saved screen

when WMSAVE_SCR() is called. It is reset to false only when WMCLOSE()

is called and when NEW_MENU() and NEW_WIN() are called.


>>.l, .r : B1_80; .t, .b : B1_25;

These fields are the current bounds or extents of an object and give

its exact position on the screen. For windows these are available as

soon as NEW_WIN() has been called, for a user saved screen as soon

as WMSAVE_SCR() has been called, but for a menu they are obviously

not available until one of either POP_MENU(), LIST_MENU() or

BAR_MENU() has been called, as the position on the screen is not

defined in the call to NEW_MENU().


         >>.tb, .tf : B1_15;

These are the textbackground and textforegroung colours for the

object. For a user saved screen these values are taken from the

Turbo Pascal TEXTATTR system variable at the time that WMSAVE_SCR()

was called. For all other objects they are taken from the appropriate

function or procedure parameter (see 'The Complete Reference Lookup'

for details).

    Each screen ram character word is organised as described below:-

CHARACTER BYTE, COLOUR BYTE (but DOS requires the low byte first!).

LOW BYTE FIRST : COLOUR BYTE, HIGH BYTE LAST : CHARACTER BYTE.


The colour byte is made up in the following way:-

High Bit 7 : blink flag 0=off 1=on --------------[0 100 1001]

      Bit 6 : -|                                      |   |

      Bit 5 :  -> Character background colour 0-7 ----|   |

      Bit 4 : -|                                          |

      Bit 3 : -|                                          |

      Bit 2 :  -> Character foreground colour 0-15 -------|

      Bit 1 : -|

Low  Bit 0 : -|


>>.horc : word;

This is the horizontal border character for the object, and will be

in screen ram format, that is low byte first, colour, high byte last 

character. For a user saved screen the colour byte is taken from the

TEXTATTR system variable when WMSAVE_SCR() is called, the character

will always be 'space', and is only used for wiping out a title  

string, if one existed, when WMTITLE() is used for a subsequent time. 

For all other objects the word is calculated from the border type and 

colour parameters, in the call to either NEW_WIN() or NEW_MENU(), as 

these both call _WMBOX_ATTRIBS().  

.PA 

Š      Fields Used By Windows and Menus Only:-

>>.bar : boolean;

This field is used to describe weather a menu is open as a bar menu

or as a pop/list menu. If it is open as a bar menu then it will be

true otherwise it is false. It is set during the call to either

POP_MENU(), LIST_MENU() or BAR_MENU() as these, in turn call, 

_MDISPLAY() and _MBDISPLAY() respectively, which is where the actual

assignment takes plase. It is always initialised to false, in the

calls to NEW_WIN() and NEW_MENU(). It will determine weather certain 

operations can be carried out on the menu or not, namely the 

displaying of comment lines, which are only allowed when you are 

displaying a menu as a bar menu.                                     

  

>>.bb, .bf : B0_15;

These fields are the border background and foreground colours and

are taken from the appropriate function or procedure parameter (see

the complete reference lookup for details).

    Each screen ram character word is organised as described below:-

CHARACTER BYTE, COLOUR BYTE (but DOS requires the low byte first!).

LOW BYTE FIRST : COLOUR BYTE, HIGH BYTE LAST : CHARACTER BYTE.


The colour byte is made up in the following way:-

High Bit 7 : blink flag 0=off 1=on --------------[0 100 1001]

      Bit 6 : -|                                      |   |

      Bit 5 :  -> Character background colour 0-7 ----|   |

      Bit 4 : -|                                          |

      Bit 3 : -|                                          |

      Bit 2 :  -> Character foreground colour 0-15 -------|

      Bit 1 : -|

Low  Bit 0 : -|


>>.tlc, .trc, .blc, .brc : word;

These are the four corner characters of the objects border, and will 

be in screen ram format, that is low byte first, colour, high byte 

last character. For all objects the word is calculated from the 

border type and colour parameters, in the call to either NEW_WIN() or  

NEW_MENU(), as these both call _WMBOX_ATTRIBS(). 

  

      Fields Used By Menus Only:-

>>.comnt : boolean;

This field will be true, for a particular menu record, if the  

MBAR_COMMENT() procedure has been used on that menu, regardless

of the menus eventual type. It is set to false in the call to

NEW_MENU() and to true in the call to MBAR_COMMENT(). Comments

cannot be erased from a menu record, but by setting this field to

false you can prevent them from being displayed, they can of course

be overwritten in each subsequent call to MBAR_COMMENT().


>>.tbc, .tfc : B0_15;

These two fields are the textbackground and foreground colours that

were originally defined, for a particular menu, in the call to

NEW_MENU(), but they have been complemented. The .tbc field is 

defined as '.tbc := .tb xor 7;' as the background colour can only

.PA

Š be a value 0-7 (00000000-00000111 binary), this ensures that each 

result bit in .tbc will be the opposite of the same bit in .tb, the 

blink flag (bit 3 .tb > 7) will remain unnafected, so that the new 

complemented colour will also blink if the flag was set in .tb. The 

.tfc field is defined as '.tfc := tf xor 15;' again this makes sure

that each bit in .tfc is the opposite of the same bit in .tf, as the

foreground colours are values 0-15 (00000000-00001111 binary).

These two complemented colour fields are used to draw the menu's

highlighted selection bar, and makes sure they are always in a 

colour that can be seen against the option text it's self.

    Each screen ram character word is organised as described below:-

CHARACTER BYTE, COLOUR BYTE (but DOS requires the low byte first!).

LOW BYTE FIRST : COLOUR BYTE, HIGH BYTE LAST : CHARACTER BYTE.


The colour byte is made up in the following way:-

High Bit 7 : blink flag 0=off 1=on --------------[0 100 1001]

      Bit 6 : -|                                      |   |

      Bit 5 :  -> Character background colour 0-7 ----|   |

      Bit 4 : -|                                          |

      Bit 3 : -|                                          |

      Bit 2 :  -> Character foreground colour 0-15 -------|

      Bit 1 : -|

Low  Bit 0 : -|

  

>>.pc : B0_15;

The menu option text's first character colour is stored in this field

its best to have the first character a different colour, so that it 

stands out, as this character on the keyboard can be used to select

that option. The field is taken from the appropriate function or 

procedure parameter (see the complete reference lookup for details).

    Each screen ram character word is organised as described below:-

CHARACTER BYTE, COLOUR BYTE (but DOS requires the low byte first!).

LOW BYTE FIRST : COLOUR BYTE, HIGH BYTE LAST : CHARACTER BYTE.


The colour byte is made up in the following way:-

High Bit 7 : blink flag 0=off 1=on --------------[0 100 1001]

      Bit 6 : -|                                      |   |

      Bit 5 :  -> Character background colour 0-7 ----|   |

      Bit 4 : -|                                          |

      Bit 3 : -|                                          |

      Bit 2 :  -> Character foreground colour 0-15 -------|

      Bit 1 : -|

Low  Bit 0 : -|

  

>>.nrow, .ncol : word;

These two fields give the length, in rows (lines) and width, in 

columns of the actual menu, as it is seen on the screen. The two

fields are calculated and filled in during the call to NEW_MENU().

For more detailed information refer to The Complete Reference Lookup.

.PA

Š >>.sumopt : word;

This field contains the total numeric length of all the option text

strings in that particular menu added together, it is calculated in 

the call to NEW_MENU(), it is used mainly for bar menus, to help

calculate the required '.gap' between options (see also .gap below).

  

>>.row : word;

This is one of the more important fields and contains the current

row number of the menu's highlighted option bar, 1 being the top

most, or for a bar menu, leftmost option. This field is available

to the user as soon as a menu has been opened, each subsequent 

time that menu is used, the highlighted bar will appear on the 

option on which it was left, thus reflecting the value of .row.

The list in a list menu will also appear in the same position as

it was left, when the menu was closed. (see .trow below).

  

>>.bar_start, .bar_end : word;

These two word fields give the offset address in screen ram to the

start and end of the highlighted menu selection bar, respectively.

only the .bar_start field is used for bar menus, .bar_end is not

defined. As mentioned above these two fields are the offset part

of the segment:offset address in screen ram, the segment part of

the address can be obtained from the predefined Winmen system

variable called 'VIDEO'. The actual screen ram contents at that


particular address, ie. the highlighted selection bar, for that

particular menu, as seen on the screen, can be accessed in the

following ways:- memw[VIDEO:ID_WM[ID]^.bar_start] := word_var;

  memw[VIDEO:IDR^.bar_start] := word_var;

  The reverse assignments are of course also valid.

  

Where memw[:] is the Turbo pascal Direct memory access word array;

       VIDEO is the Winmen system variable containing the segment

       base address for screen ram.

       ID_WM[] is the Winmen pt_wmrec pointer array (see ID_WM[],

       pt_wmrec and wmrec);

       ID is the menu identifier byte as returned from NEW_MENU();

       IDR is a pointer variable of type pt_wmrec (see pt_wmrec and

       wmrec).

  

>>.first : boolean;

This flag tells various functions and procedures in the Winmen unit,

weather or not that particular menu has ever been opened, so that the

positioning of the highlighted menu bar can be determined, the first

time a menu is opened the bar is positioned at the top of the menu

over option one, on subsequent opens the bar is put back in the same

position as when the menu was closed, this is also the case for a

list menus option text, where it exceeds the visible options. The

flag is set to 'true' for menu never opened (during the call to

NEW_MENU()) and 'false' if it has been opened (during the first call

to _MDISPLAY() or _MBDISPLAY, which are called by POP/LIST_MENU(),

and BAR_MENU() respectively).

.PA

Š      Fields Used By Pop and List Menus Only:-   

>>.trow : word;

This field is used to hold the number, of the menu option, which is 

currently at the top of the visible menu. For a Pop menu this will

always be row one, and for a List menu it will depend upon how far

the list has been scrolled, towards the bottom of the list. This 

field is initialised in the calls to POP_MENU() and LIST_MENU()

which both call _MDISPLAY(), it is altered and used by almost all

of the functions and procedures that support POP/LIST_MENU(). The

first time a menu is opened as a List menu .trow and the actual

visible top menu option, will be one. Each subsequent time the menu 

is opened as a List menu, .trow and the actual visible top menu 

option, will be the same as when the menu was closed the last time.

(See also .row above).

  

>>.rows_vis : B1_23;

This gives the actual number of options, that are visible on the 

screen for a particular menu. For a menu used as a Pop menu this 

will always be equal to the total number of options that were 

specified, in the call to NEW_MENU(). For a menu used as a List menu 

this will always be equal to the number of visible options parameter

specified in the call to LIST_MENU(). The .rows_vis field becomes

available after the first call to either POP_MENU() or LIST_MENU() 

fotr that particular menu and once again is used by many of the 

functions and procedures that support POP/LIST_MENU().


      Fields Used By Bar Menus Only:-

>>.ncolc : byte;

This field becomes available after the call to MBAR_COMMENT(), it

contains the length of the longest string of comment text that was

sent to MBAR_COMMENT(). All the comment strings are padded out to

make them the same length as the longest one, in the call to

MBAR_COMMENT(). The comment text is displayed, and the remainder up

to the end of the bar menu is again padded, unless of course the

comment text strings are longer than the bar menu, in which case

the comment text will be truncated at the end of the menu. The 

comment text has to be padded, to the end of the bar menu, to enable

the menu to slide properly, during a call to WMSLIDE(). You may also

find it usefull to read the section on MBAR_COMMENT() in the 

'Complete Reference Lookup' and the ID_MC[] description in the

section 'Winmen Declared Variables'.

  

>>.gap : B1_80;

This field contains the minimum gap, given in screen characters, 

between each, before the first and after the last option on a bar 

menu. If the remainder of (blen-.sumopt) is not equaly divisable 

(in integer terms) by the (number of options+1) then the quotiant is

used for the .gap field and the integer remainder is added to the

gap after the last option, when the bar menu is displayed. The blen           

variable mentioned above is not actualy a record field, it is just

there to represent the length of a particular bar menu, it is also

the bar menu length parameter as passed to the BAR_MENU() function 

by the user, the .sumopt field is given above. This field becomes 

available for a particular bar menu after the call to BAR_MENU().

.PA

Š >>.cols_vis : word;

The .cols_vis field will always be equal to the bar menu length, 

which was passed to the BAR_MENU() function as one of its parameters.

  

      Fields Used By Windows Only:-

>>.x, .y : byte;

These two fields give the column and row position of the text cursor

that is used with the WWRITE(); WWRITELN(); and WGOTOXY() procedures

and is relative to the top left corner of the window or user screen.

Do'nt forget that position 1,1 for a user screen is the absolute top

left corner, whereas for a window it's the top left character inside

the border. These two fields have no effect or relationship with the

Turbo Pascal text window cursor, which is positioned using the

gotoxy() procedure. Both fields are set to 1,1 as soon as that

window or user screen is defined in the call to either NEW_WIN(); or

WMSAVE_SCR(); and are available thereafter, untill that object is

destroyed with WMDELETE();


>>.lt, .rt : B1_80; .tt, .bt : B1_25;

These four fields are temporary values used by the WOPEN() procedure

and are the starting positions for when the window is exploded onto

the screen. The four values will always be as follows:-

    The .lt field will always be equal to the horizontal centre point 

    of the window - 1.

    The .rt field will always be equal to the horizontal centre point 

    of the window + 1.                                                

    The .tt field will always be equal to the vertical centre point 

    of the window - 1. 

    The .bt field will always be equal to the vertical centre point 

    of the window + 1. 

These four basic values are passed on to the _WBOX_ON() procedure

but are only altered when a window is moved or slid using WMMOVE()

or WMSLIDE() respectively.


>>.max : B1_80;

This field contains either the total length or height of a window

in screen characters, depending upon which is the larger, hense max. 

It is used in the WOPEN() procedure as a loop count, while calls to 

the _WBOX_ON() procedure are made, so that the window can be exploded 

to the correct size.

  

>>.cp : word;

This field holds the offset part, of the segment:offset address, 

which is the exact centre of the window in screen ram. The segment

part of the address is held in the Winmen system variable 'VIDEO'

and is dependant upon the graphics card being used in the PC. It is

used again in the WOPEN() procedure, to enable the centre character

of the window to be filled with the windows textbackground colour,

prior to the window being exploded onto the screen, this is because

the smallest rectangle/box that we can put on the screen using the

_WBOX_ON() procedure, and wipe off with the windows background colour

again using the _WBOX_ON() procedure, is 3x3 characters, this leaves 

the centre character the wrong colour, thus the need for .cp.

.PA

Š      This ends the discription of the wmrec record fields.


      >>maprec = record;

      Firstly, before we start to go into the maprec type, I think we need to

      explain the basic principles and ideas behind the whole concept of a 3D

      screen map.

For the purposes of simplicity a window, user screen or menu will

      all be refered to as objects, from now on, unless otherwise stated.

To enable the Winmen Unit to manipulate objects on the text screen by

      moving and sliding, is a fairly simple task, even opening and closing,

      overlapping objects, as long as it's in a logical, "last open first

      shut" sequence, is reletively straight forward. When we start floating

      obscured objects to the surface, closing objects that are covered by

      other objects, "first open first shut", or removing partially or fully

      obscured objects from the display, while still leaving the screen

      intact, we need to keep track of exactly where each open object is on

      the screen and what open objects there are, above and below, each open

      object and weather or not they overlap, above and below in this sense is

      meant logically, as the screen has no phisical depth.

The type of structure needed for this task has to be able to view

      the text screen as a three dimensional system. The basis for this

      structure is the array of pointers:-


>>pt_maprec = ^maprec;

>>MAP : array[0..2000] of pt_maprec;

The 2000 pointers defined in this array are each capeable of pointing

to a "maprec" type record variable, which is the subject of this

section.  The 2000 pointers are needed to cover the screen completely

that is 80 columns x 25 rows = 2000 pointers, this array forms the

base or platform on which our three dimensional structure is built.

    If no objects are open on the screen, then all the pointers in the

MAP[] array will be "nil". If an object is opened and say it's the

only object on the screen, then all of the objects surface will be

logicaly next to the MAP[] array, this will always be the case as

long as none of the open objects overlap each other.

    Each time an object is opened onto the screen, in the maner

described above, a "maprec" will be created for each character cell

on the objects surface area. Each of these "maprecs" is linked into

the MAP[] pointer array, by passing the address of the newly created

"maprec" to the MAP[] pointer variable, whoose index, corresponds to

the screen position of that particular character cell. For example,

if an object were positioned on the screen at say x5,y5 the address

of the "maprec", for the top left most character in the object, would

be passed to the pointer variable at MAP[((y-1)*80)+x-1] which is,

MAP[324], we have to take off the 1 at the end as the MAP[] array

starts at MAP[0] not MAP[1], the 80 represents the columns accross

the screen.

    After the "maprec" is linked in, as explained above, the three

fields are then filled in as follows:-

.PA

Š     >>.ID : byte;

    This is the objects ID byte, sent back from the call to NEW_WIN();

    or NEW_MENU(); or sent to WMSAVE_SCR(); if the object is a user

    screen (ID < 20), when the object was defined. This tells us

    which object owns that particular "maprec".


    >>.sc_inx : word;

    This field is an index into the owning objects ID_SC[] background

    screen array and tells the system which screen ram format word

    to display at the 3D screen MAP[] position that this particular

    "maprec" is linked into, either directly, if the object is

    logically touching the MAP[] array (first open), or indirectly,

    if the object is an overlaping one, in which case its "maprec"

    will be further along the linked list of "maprecs", whilst still

    being in the same MAP[map_inx] position, how far along the list a

    "maprec" is will depend on how many objects there are directly

    underneath it, where the character cells actually overlap. The

    screen ram format word at this particular index is not forced to

    be displeyed, it may just be passed to another objects ID_SC[]

    background screen array, depending on the type of operation

    being carried out.

       The ID_SC[] background screen array, for any object, contains a

    copy of the screen image that is directly underneath that

    particular object. For more details on this array and the pointer

    types associated with it refer to the sections on "screen",

    "pt_screen" and "ID_SC[]".


    >>.next : pt_maprec;

    This field is a pointer to the record type "maprec", just as the

    2000 pointers in the MAP[] array.

       As discused above, each time an object is opened onto the

    screen, a "maprec" will be created for each character cell on the

    objects surface area, initialy this ".next" pointer field is set

    to nil, this indicates that this "maprec" is the last one in the

    linked list, at that particular 3D screen MAP[] position. This

    also tells us that the object that owns this particular "maprec"

    must be the topmost one at that particular 3D screen MAP[]

    position, i.e. the character cell that corresponds to that 3D

    screen MAP[] position is visible on the screen, as opposed to

    being hidden by an overlaping object.

       The ".next" field will only be passed the address of another

    "maprec" under the following circumstances:-


       1) If an object is opened onto the screen and it overlaps any

  other objects, a new "maprec" will, as before, be created

  for for each character cell location on the objects surface

  area, having done this, the linked list at each appropriate

  3D screen MAP[] position, corresponding to each character

  cell location on the objects surface area, will in turn, be

  searched to find the last "maprec" in that particular linked

  list, once this has been done, the ".next" field of this

  last "maprec" is passed the address of the new "maprec" that

.PA

Š   corresponds to that same 3D screen MAP[] position. This

  makes the linked lists grow outwards from the 3D screen

  MAP[], thus giving us our three dimensional system, which

  allows us to see what is above or below an object at any

  particular character cell or 3D screen MAP[] position.


       2) If an object is closed or removed from the screen, then

  every "maprec" owned by that object will be deleted. this

  will of course leave gaps in the affected linked lists,

  unless that object was logicaly next to the MAP[] array

  and with no other objects overlaping it (first open), in

  which case the linked list at that particular 3D screen

  MAP[] position will no longer exist and the appropriate

  MAP[] array pointer at that position will be given a nil

  value. If the "maprec" deleted was in the middle of a

  linked list then the address contained in its ".next"

  field (address of the next "maprec" in that list) will be

  passed to the ".next" field of the "maprec" that was

  immediatly before it in that linked list, thus rejoining the

  list. If on the other hand the "maprec" deleted was on the

  end of a list then all we need to do is give the ".next"

  field of the new last "maprec" in the list a nil value, to

  indicate that it is now the end of the list.


       3) The final case that involves the manipulation of the ".next"

  pointer field is when objects are floated to the surface or

  moved or slid around the screen. This time we wont actualy

  be creating or destroying any "maprecs", just moving them

  around to new positions on the END of existing linked lists

  on the 3D screen MAP[] array.

     All of these object manipulation operations demand that

  the object is on the top of the pile i.e. completely

  visible on the screen and not obscured at any character cell

  location by any other object, the exceptions to this rule

  are the WMMOVE(); procedure and of course the WMFLOAT();

  procedure, which both bring the object to the surface

  themselves, the WMSLIDE(); procedure does not float the

  object to the surface or carry out any operations on the

  objects "maprecs" at all, the user has to do this himself,

  this is for speed considerations in certain circumstances,

  unlike the WMFLOAT() and WMMOVE(); procedures, which do

  carry out all the required "maprec" manipulation operations

  for you, the WMMOVE(); procedure can also be used when

  objects are closed, this will not affect the 3D screen

  MAP[], or any "maprecs", as none exist while the object is

  closed. For more detailed information on the WMSLIDE();

  WMFLOAT(); and WMMOVE(); procedures, see the relevant

  sections in the "Complete Reference Lookup".

     Briefly, what actualy happens when you float an object to

  the surface is, the "maprecs", that are owened by that

  particular object, in the linked lists, at the affected 3D

.PA

Š   screen MAP[] positions, are also floated to the surface,

  or rather to the END of each affected list, this is done

  by transfering the address contained in the ".next" field of

  the "maprec" below the one being floated, to the ".next"

  field of the "maprec" that is currently at the end of the

  list, replacing the nil value, we then take the address

  contained in the ".next" field of the "maprec" being

  floated, which is now on the end of the list, and put it

  in the ".next" field of the "maprec" that was below it in

  the list, lastly the ".next" field of the "maprec" that

  was floated, which is now at the end of the list, is given a

  nil value, to end the list, this is done for each affected

  3D screen MAP[] position.  The "maprecs" are not the only

  things that have to be manipulated, the ID_SC[] background

  screen array that is associated with each affected object,

  also has to be updated, with new information, at each

  character cell location affected by the float, this is

  done at the same time, in a similar maner.

     Moving an object does not cause as many problems as you

  might imagine, firstly we just float the object to the

  surface, as above, then instead of manipulating the objects

  "maprecs" further, we delete them, move the object, and

  create a new "maprec", on the end of each appropriate linked

  list, at the relevant 3D screen MAP[] position, one for each

  character cell location on the objects surface, doing it

  this way means we can use existing routines within the

  Winmen Unit and seems logical, as the object starts off on

  the top layer and finishes on the top layer, if we had

  chosen to move all the objects "maprecs" to the new

  positions directly and done away with the float, delete and

  create, we would have had to look at transfering the object

  along with its "maprecs" and ID_SC[] background screen array

  words, from the level it was on, to the same relative level

  in its new position, a much more complex and time consuming

  task. The WMSLIDE(); procedure also demands the same sort

  of considerations as the WMMOVE(); procedure i.e. the

  object will need to be brought to the surface, before it

  is slid.


    This ends the description of the "maprec" fields.


      Hopefully the above text will give you a fairly clear idea of how the

      Winmen Unit sees the text screen as a three dimensional system, with

      the aid of the 3D screen MAP[] pointer array as its base and linked

      lists of "maprecs" growing outwards from the MAP[] array, linked using

      the "pt_maprec" pointers, to form its logical depth.

The diagram below may help to clear up any doubts, following that

      are examples on how to access the 3D screen MAP[] pointer array and the

      linked lists of "maprecs" adjoining it.

.PA

Š





                          PAGE 28 TO BE PRINTED HERE






.PA

Š





                          PAGE 29 TO BE PRINTED HERE






.PA

Š     begin

       IDB := MAP[map_inx]^.next^.ID;    \

OR                        \

       pt_rec := MAP[map_inx];             \ FOR A DOUBLE MAPREC LEVEL

       IDB := pt_rec^.next^.ID;             \(SEE DIAGRAM ABOVE)

OR                           \

       pt_rec := MAP[map_inx]^.next;          \

       IDB := pt_rec^.ID;                      \

       /

       scr_inx := MAP[map_inx]^.next^.sc_inx; /

       etc....                               /

    end;                                    /


    begin

       IDB := MAP[map_inx]^.next^.next^.ID;\

OR                          \

       pt_rec := MAP[map_inx];               \ FOR A TRIPLE MAPREC LEV

       IDB := pt_rec^.next^.next^.ID;         \(SEE DIAGRAM ABOVE)

OR                             \

       pt_rec := MAP[map_inx]^.next^.next;      \

       IDB := pt_rec^.ID;                        \

  \

       scr_inx := MAP[map_inx]^.next^.next^.sc_inx;\

       etc....                                     /

    end;                                          /


      This should give you a good working knowlege of how to access the

      three dimensional text screen system, its arrays, maprecs and pointers.

      It would pay dividends to study the above sections throughly, so that

      you can get the maximum from this very powerful set of Winmen types

      and variables.


      >>pt_mtext = ^mtext;

      This is a pointer type, when a variable of this type is defined it will

      point to a variable of type mtext. The mtext type along with a full

      discription of how to use a pointer of type pt_mtext, is given in the

      description of 'mtext' above.  More detail can be obtained by reading

      the descriptions of NEW_MENU() and MBAR_COMMENT() in the section 'The

      Complete Reference Lookup'.


      >>pt_mmenu = ^mmenu;

      This is a pointer type, when a variable of this type is defined it will

      point to a variable of type mmenu. The mmenu type along with a full

      discription of how to use a pointer of type pt_mmenu, is given in the

      description of 'mmenu' above.


      >>pt_wmrec = ^wmrec;

      This is a pointer type, when a variable of this type is defined it will

      point to a variable of type wmrec. The wmrec type along with a full

      discription of how to use a pointer of type pt_wmrec, is given in the

      description of 'wmrec' above.

.PA

Š      >>pt_scr = ^screen;

      This is a pointer type, when a variable of this type is defined it will

      point to a variable of type screen. The screen type along with a full

      discription of how to use a pointer of type pt_scr, is given in the

      description of 'screen' above.


      >>pt_maprec = ^maprec;

      This is a pointer type, when a variable of this type is defined it will

      point to a variable of type maprec. The maprec type along with a full

      discription of how to use a pointer of type pt_maprec, is given in the

      description of 'maprec' above.


      Winmen Declared Global Variables (Additional to Turbo Pascal Variables)

      ------------------------------------------------------------------------


      Each of the variables defined by the Winmen unit are briefly discussed

      in this section. For more detailed information, see the descriptions of

      the functions and procedures that depend on these objects in Chapter 2

      "The Windows And Menus Complete Reference Lookup". Where this is not

      applicable, a full description is given in this section.


      var

wt      : array[0..100] of word;  {*TEMP ARRAY LEAD/TRL EDGE DATA*}

VIDEO   : word;                   {*SEG BASE ADDRESS OF VIDEO RAM*}

scr     : text;                   {*FHANDLE FOR SCREEN*}

log     : text;                   {*FHANDLE MEM LOG FILE (DEBUG)*}

comment : string;                 {*STRING FOR WMMEM_STAT() COMNTS*}

IDG     : byte;                   {*PTR ARRAY INDEX USED IN INIT*}

MENU_EXIT_BY_CURSOR : boolean;    {*FALSE=NO TRUE=YES DEFAULT=TRUE*}

MENU_ACT_ON_PC : boolean;         {*FALSE=NO TRUE=YES DEFAULT=TRUE*}

CLOSE_WITH_REMOVE : boolean;      {*FALSE=NO TRUE=YES DEFAULT=FALSE*}

IDW_active,IDM_active,            {*HOLDS ACTIVE WINDOW/MENU IDB*}

gdriver,gmode : integer;          {*GRAPH DRIVER & MODE DETECTED*}

ID_WM : array[0..255] of pt_wmrec;{*ARRAY OF RECORD PTRS*}

ID_MM : array[0..255] of pt_mmenu;{*ARRAY OF PTRS TO MENU OPT TEXT*}

ID_SC : array[0..255] of pt_scr;  {*ARRAY OF PTRS TO SAVED SCR DATA*}

ID_MC : array[0..255] of pt_mmenu;{*ARRAY PTRS TO BAR MENU COMNTS*}

MAP : aray[0..2000] of pt_maprec; {*3D SCREEN MAP ARRAY OF POINTERS*}


      >>wt : array[0..100] of word;

      This array is used as temporary storage for the screen ram format data

      that is just about to dissapear underneath the leading edge of a window

      menu or user saved screen area, during a WMSLIDE() operation, after

      which, this data is merged with that objects proper ID_SC[] 'screen'

      array. This is explained in more detail in the description of the

      WMSLIDE() and associated procedures, in 'The Complete Reference Lookup'. 


      >>VIDEO : word;

      This word variable contains the segment base address of video ram and 

      is dependant upon what type of graphics addapter you have in your PC.

      It will be one of two values:-

$B000 : for a mono type addapter.

$B800 : for a colour or any other type addapter.

.PA

Š      This variable is set during the initialisation of the Winmen unit, so

      dont tamper with it during a programme, unless you are shure that what

      you are doing is correct.


      A word of warning, the Amstrad PPC portable machines come under the 

      mono type addapter, and for the most part, programmes that use the 

      Winmen unit to display windows and menus, function as they should, 

      on these machines, until one uses the Turbo Pascal readln procedure

      in a Winmen window, this for some reason, unknown to the world outside

      of Amstrad, completely scrambles the video ram, all suggestions will

      be gratefully received. Every other aspect works 100%

 

      >>scr : text;

      This text type file variable is assigned to crt, again in the initiali-

      sation section of the Winmen unit. By using this file variable in all

      your write procedures, thus:- writeln(scr,'quick text'); you will

      greatly increase the speed of writing text to the screen.


      >>log : text;

      This text type file variable is assigned to a file called 'Memory.Log'

      during the initialisation section of Winmen. The Winmen unit will then

      automatically write memory and other information to this file if at

      any time a memory allocation or similar error occures during the runtime

      of a programme that uses the Winmen unit. Full details of this file

      variable and how and when to use it are given in the description of the

      WMMEM_STAT() procedure, in the section 'The Complete Reference Lookup'.


      >>comment : string;

      this string variable has been predefined for use with the WMMEM_STAT()

      procedure, and is used by the Winmen unit for this purpose. Refer to

      the WMMEM_STAT() procedure in 'The Complete Reference Lookup' for full

      details.


      >>IDG : byte;

      This variable has been defined purely for use in the Winmen units

      initialisation section, and is used as an index when the pointer arrays

      are initialised to nil, see below.


      >>MENU_EXIT_BY_CURSOR : boolean;

      This switch gives the user the option of being able to exit list and pop

      menus using the cursor left and right keys, as well as the escape key,

      in fact this is the default.  It is sometimes more useful to be able to

      turn this feature off, especialy if you are using a keyboard type mouse,

      like the Amstrad one, as using a mouse of this type makes using the

      menus very dificult with this feature turned on, because each time the

      mouse is moved left or right, the menu will close, as the mouse returns

      the same ascii characters as the keyboard for left and right cursor

      movement.

MENU_EXIT_BY_CURSOR := true; Menus will exit using cursor or mouse

left/right keys.

MENU_EXIT_BY_CURSOR := false; Menus will not exit when cursor/mouse

left/right keys are used.

MENU_EXIT_BY_CURSOR := true; default.

.PA 

Š      >>MENU_ACT_ON_PC : boolean;

      This switch gives the user control over weather the menus will return

      the option number, when a menu option is chosen using the first

      character method. Normaly a users routine that calls a menu function

      will act on the option returned immediatly, this is quite correct, but

      can sometimes be a bit disconserting, especially if the users next

      operation is to remove the menu in question. By turning this feature

      off the menu functions will not return the option number of an option

      chosen with the first character method, therefore the users routine

      cannot act on it, this effectively gives the user a chance to verify

      that the option the highlighted menu bar has moved to is the one he

      actualy wants. The highlighted menu bar will always move to the option

      that was chosen with the first character method, regardless of how

      this switch is set.

MENU_ACT_ON_PC := true; Menu functions will return the number of

the option chosen using the first character method. Don't forget if

there is more than one option with the same first character, it is

the number of the first one in the list that will be returned.

MENU_ACT_ON_PC := false; Menu functions will not return the number

of the option chosen using the first character method.

MENU_ACT_ON_PC := true; Default.


      >>CLOSE_WITH_REMOVE : boolean;

      This switch gives the user two diferent methods of closing objects and

      removing them from the screen, they are:-

CLOSE_WITH_REMOVE := false; All objects will be closed by firstly

floating them to the surface with WMFLOAT() and then restoring the

objects ID_SC[] background screen array using WMREST_SCR(); to

effectively remove them.

CLOSE_WITH_REMOVE := true; All objects will be closed by using the

WMREMOVE(); procedure, this makes it appear as if the object is

being removed from the back of the screen, instead of from the

front, as the other method does.

CLOSE_WITH_REMOVE := false; Default.

      Any object, that for some reason, does not have any "maprecs" linking it

      into the Winmen 3D screen map system, can not be WMFLOATed or WMREMOVEd,

      depending on the system switch above, as both these routines will exit,

      with no action, if no "maprecs" exist for the object in question. The

      object will however still be closed, by WMCLOSE(); but using just the

      WMREST_SCR(); procedure as its main effort.

WARNING... If the WMCLOSE() procedure reveals that no "maprecs"

      exist, for the object, at the appropriate 3D screen map locations, then

      it is forced to make the assumption that the object is not obscured by

      any other object, as no other facts are available to it, so a close by

      using WMREST_SCR(); to restore the objects ID_SC[] background screen

      array should be sufficient. If the object is obscured by others, either

      partially or fully, then you can expect some display corruption at some

      stage, possibly sooner rather than later.

.PA

Š      >>IDW_active, IDM_active : integer;

      These two integer variables will, after initialisation, always contain

      the ID reference byte value of the currently active window and menu

      respectively, if none are active they are set to -1, else they will be

      a value in the range 0-255. They are both initialised to -1 by the

      Winmen unit. The ID reference byte for a window, menu or user saved 

      screen area is the value returned from NEW_WIN() or NEW_MENU() or the  

      value sent to WMSAVE_SCR(), for a user screen (range 0-19). By active

      we mean open and in use.


      >>gdriver, gmode : integer;

      These two variables are used to recieve the graphics driver and its

      current mode values, in the call to detectgraph() in the Winmen units

      initialisation section, and are used to determine a suitable value for

      the 'VIDEO' segment base address variable (see above).


      >>ID_WM : array[0..255] of pt_wmrec;

      This is an array of pointer variables, each one, once dynamically

      allocated, will point to a structure of type wmrec. This is all done

      by the Winmen unit and need not concern the user, although detailed

      information on this array and how to use it, with its pointers is

      given in the description of the 'wmrec' type, above.


      >>ID_MM : array[0..255] of pt_mmenu;

      This is an array of pointer variables, each one, once dynamically

      allocated, will point to a structure of type mmenu. This is all done

      by the Winmen unit and need not concern the user, although detailed

      information on this array and how to use it, with its pointers is

      given in the description of the 'mmenu' type, above.                     


      >>ID_SC : array[0..255] of pt_scr;

      This is an array of pointer variables, each one, once dynamically

      allocated, will point to a structure of type screen. This is all done

      by the Winmen unit and need not concern the user, although detailed

      information on this array and how to use it, with its pointers is

      given in the description of the 'screen' type, above.                     


      >>ID_MC : array[0..255] of pt_mmenu; 

      This is an array of pointer variables, each one, once dynamically

      allocated, will point to a structure of type mmenu. This array and the

      pointers associated with it, work in exactly the same way as those for

      the ID_MM[] pointer array. Full information on how to use this array

      and its pointers can be found in the description of the 'mmenu' type

      in the 'Winmen Declared Types' section above. All the examples given

      in the 'memnu' description are equaly valid for this array, just swap

      ID_MM[] for ID_MC[], and IDM for IDMC each time. The only diference

      being, that the pt_mmenu pointer variables will point to menu comment

      lines rather than actual menus. In view of this the structure layout

      and access technique will differ slightly.

.PA

Š The diagram below will give you a better idea of how the mmenu array

      is used and how to access it correctly for a particular bar menu

      comments structure, assuming that menu has been set up using the

      NEW_MENU() function and that bar menu comments have also been defined

      using the MBAR_COMMENT() procedure:-


   OPTION, STRING

      IDMC^[0..402][0..80]             WORDS

      [0..80]

0123456789............................................80

       0menu comment line = IDMC^[0][0..16]

       1another comment

       ARRAYS  2and another line  --------------------------->

      [0..402] 3penultimate line

      (MENUS   4last comment line = IDMC^[4][0..16]

       OPTION  5       |

       NUM-1)  6       |

       7       |

       8       |

       9       V


      The above diagram assumes that you have defined a pointer somewhere in

      your programme, like this:-

      var

IDMC : pt_mmenu; (see pt_mmenu above)

      This then gives us a nil pointer variable to a structure of type mmenu

      which is array[0..402][0..80] of word.

      To enable us access the actual data for the above bar menu comments,

      assuming the menu has been set up using NEW_MENU(), and the comments

      with MBAR_COMMENT(), you would then do the following:-

      IDMC := ID_MC[ID];


      Where ID is the reference byte returned from NEW_MENU() when the menu

      in question was set up, and ID_MC[] is this array of pointers, each one

      of which could point to a separarte bar menu comments structure.

      This assignment gives the IDMC pointer the start address for the above

      bar menu comments structure.

You could of course not bother with defining the IDMC pointer and just

      use the array of pointers to reference the above bar menu comments

      structure, like this:-

      ID_MC[ID]^[0][0..16], this is equivalent to IDM^[0][0..16], but I think

      it's neater to define the pointer.

The [0..16] range is only there to indicate the width of the above

      bar menu comments structure, all comment lines are padded to the same

      length as the longest one (see the .ncolc wmrec field in the 'Winmen

      Defined Types' section, for more info), you would only normaly use one

      number for the index thus:-

      IDM^[0][0], this would access word 0 in line 0 of the above menu, which

      is the word describing the character 'm' in 'menu comment line'. As can

      be seen the majour difference is that the bar menu comment words begin

      at IDMC^[0][0] or array [0] word [0], whereas the menu options, which

      use the ID_MM[] pointer array begin at IDM^[1][1] or array [1] word [1],

.PA

Š      see mmenu above, so you will have to remember that the index for

      accessing bar menu comment strings in the IDMC^[index1][index2]

      structure will always be one less (-1) than the actual menu option that

      it pertains to, ie. IDMC^[option-1][character-1], if you remember this

      idea you will not go far wrong.

You will see all the above techniques used from time to time in the

      example programmes supplied with the Windows and Menus unit, it is a

      very important aspect of the unit and the descriptions here, of all the

      new types and variables, will enable you to extract the most benefit

      from it, but it will require a little studying.


      >>MAP : array[0..2000] of pt_maprec;

      This array of pointers is the base for the complete three dimensional

      screen maping system operated by the Winmen Unit, for full details on

      this array and the associated "maprec" record structure and "pt_maprec"

      pointers, see the sub-section on the >>MAP[] array under the main

      section on the >>maprec type, all these are in the "Winmen Declared

      Types" section.

.PA

Š      Winmen Initialisation

      ------------------------------------------------------------------------


      Below is an exact copy of the Winmen Unit Initialisation section, by

      studying it you can see exactly how and which of the Winmen global type

      variables are initialised, and what they are initialised to:-


      var

rec_pt : word;


      begin

assign(log,'MEMORY.LOG'); {*OPEN A MEMORY LOG FILE FOR DEBUGING ONLY*}

comment := 'TURBO PASCAL WINDOWS & MENUS MEMORY LOG';

comment := comment + chr(13) + chr(10);

comment := comment + 'Memory Condition At Initialization:-';

WMMEM_STAT(comment,log,'R');


assigncrt(scr);           {*OPEN A FAST TEXT FILE FOR THE SCREEN*}

rewrite(scr);

IDW_active := -1;         {*SET NO WINDOWS ACTIVE*}

IDM_active := -1;         {*SET NO MENUS ACTIVE*}

for IDG := 1 to 255 do

begin

    ID_WM[IDG-1] := nil;   {*INITIALISE ALL POINTER ARRAY ELEMENTS*}

    ID_MM[IDG-1] := nil;   {*TO NIL                               *}

    ID_SC[IDG-1] := nil;

    ID_MC[IDG-1] := nil;

end;

ID_WM[255] := nil;

ID_MM[255] := nil;

ID_SC[255] := nil;

ID_MC[255] := nil;


rec_pt := 0;

while(rec_pt < 2000) do   {*INITIALISE 3D SCREEN MAP BASE POINTERS*}

begin                     {*TO NIL                                *}

    MAP[rec_pt] := nil;

    inc(rec_pt);

end;

                                   {*GET INSTLD GRAPHICS CARD DRIVER & MODE*}

detectgraph(gdriver,gmode);

case gdriver of           {*CHECK DRIVER AGAINST MONO LIST*}

    MCGA,HercMono,         {*SET VIDEO ADDR FOR A MONO TYPE ADAPTER*}

    EGAMono,-2 : VIDEO := $B000;

    else

       VIDEO := $B800;     {*SET VIDEO ADDR FOR COLOUR TYPE ADAPTER*}

end;

                                   {*SET SO POP/LIST MENUS EXIT WITH L/RCURS*}

MENU_EXIT_BY_CURSOR := true;

MENU_ACT_ON_PC := true;   {*SET SO IF PIC CHAR SELECT, TAKE ACTION*}

CLOSE_WITH_REMOVE := false;

      end {end unit}.              {*SET SO WMCLOSE USES WMFLOAT & REST_SCR*}

.PA

Š      Winmen Quick Reference Lookup

      ------------------------------------------------------------------------


      Each of the subsections below are in alphabetical order, the function or

      procedure name is given along with its parameters and syntax.



      Windows Functions


NEW_WIN(l : B1_78; t : B1_23; r : B3_80; b : B3_25;

btype : B1_4;

bb,bf,tb,tf : B0_15) : byte;



      Windows Procedures High Level


WCLRSCR(IDB : byte);


WCOLOUR(IDB : byte;tb,tf : B0_15);


WEXPLODE(l : B1_78; t : B1_23; r : B3_80; b : B3_25;

  btype : B1_4;

  bb,bf,tb : B0_15);


WGOTOXY(IDB,x,y : byte);


WOPEN(IDB : byte);


WSELECT(IDB : byte);


WWRITE(IDB : byte; stg : string);


WWRITELN(IDB : byte; stg : string);



      Windows Procedures Low Level


_WBOX_ON(lt : B1_80; tt : B1_25; rt : B1_80; bt : B1_25;

  tlc,trc,blc,brc,horc,verc : word);


_WCHK_MIN_SIZE(proc : string;

l : B1_78; t : B1_23; r : B3_80; b : B3_25);


_WSCROLL_UP(IDB : byte);



      Menus Functions


BAR_MENU(IDB : byte;l : B1_78;t : B1_23;blen : B1_80) : W0_400;


LIST_MENU(IDB : byte;l : B1_78;t,rows_vis : B1_23) : W0_400;

.PA

Š NEW_MENU(btype : B1_4;

  bb,bf,tb,tf,pc : B0_15;

  mt : pt_mtext;

  rowt : W0_400) : byte;


POP_MENU(IDB : byte;l : B1_78;t : B1_23) : W0_400;



      Menus Procedures High Level


MBAR_COMMENT(IDB : byte;mtc : pt_mtext);


MCHANGE_CHAR(IDB : byte;

      row : word; col : byte;

      new_char : char;

      tb,tf : B0_15);


MPIC_COL(IDB : byte;pc : B0_15);



      Menus Procedures Low Level


_MBBAR_END(IDB : byte);


_MBBAR_HOME(IDB : byte);


_MBBAR_LEFT(IDB : byte);


_MBBAR_OFF(IDB : byte);


_MBBAR_ON(IDB : byte);


_MBBAR_RIGHT(IDB : byte);


_MBDISPLAY(IDB : byte);


_MCHK_ON_SCREEN(IDB : byte;proc : string;

l : B1_78;t : B1_23;nrow : B1_25);


_MDISPLAY(IDB : byte);


_MLBAR_BLST(IDB : byte);


_MLBAR_END(IDB : byte);


_MLBAR_HOME(IDB : byte);


_MLBAR_TLST(IDB : byte);


_MLMOV_DO(IDB : byte;move : char);


_MLMOV_UP(IDB : byte;move : char);

.PA

Š _MPBAR_END(IDB : byte);


_MPBAR_HOME(IDB : byte);


_MPLBAR_DO(IDB : byte);


_MPLBAR_OFF(IDB : byte);


_MPLBAR_ON(IDB : byte);


_MPLBAR_UP(IDB : byte);



      Common Functions Low Level


_WMCHK_FOR_MREC(IDB : byte) : boolean;


_WMSAVE_SCR(l : B1_80; t : B1_25 r : B1_80; b : B1_25) : pt_scr;



      Common Procedures High Level


WMADD_MREC_ALL(IDB : byte);


WMATTRIBS(IDB : byte;

   btype : B1_4;

   bb,bf,tb,tf : B0_15);


WMCLOSE(IDB : byte);


WMDELETE(IDB : byte);


WMDEL_MREC_ALL(IDB :byte);


WMFLOAT(IDB : byte);


WMMEM_STAT(comment : string; var handle : text; r_a : char);


WMMOVE(IDB : byte; l : B1_78; t : B1_23);


WMREMOVE(IDB : byte);


WMREST_SCR(IDB : byte;l : B1_80; t : B1_25; r : B1_80; b : B1_25);


WMSAVE_SCR(IDB : byte; l : B1_80; t : B1_25; r : B1_80; b : B1_25);


WMSLIDE(IDB : byte; dir : char; nchar : byte);


WMTITLE(IDB : byte; bb,bf : B0_15;title : string);

.PA

Š      Common Proocedures Low Level


_WMADD_MREC(IDB : byte; sc_inx,map_inx : word);


_WMBOX_ATTRIBS(btype : B1_4;

bb,bf : B0_15;

var tlc,trc,blc,brc,horc,verc : word);


_WMCHK_EXIST(IDB : byte;proc : string);


_WMCHK_MEM(proc : string;blk_reqd : word);


_WMCHK_TYPE(IDB : byte;proc : string;typ : char);


_WMCOPY_SCR(l1 : B1_80; t1 : B1_25; r : B1_80; b : B1_25;

     l2 : B1_80; t2 : B1_25);


_WMDEL_MREC(IDB : byte; map_inx : word);


_WMREST_SCR(pt_sc : pt_scr; 

     l : B1_80; t : B1_25; r : B1_80; b : B1_25);


_WMSLIDE_D(IDB,nchar,l,t,r,b,ncol,nrow : byte);


_WMSLIDE_L(IDB,nchar,l,t,r,b,ncol,nrow : byte);


_WMSLIDE_R(IDB,nchar,l,t,r,b,ncol,nrow : byte);


_WMSLIDE_U(IDB,nchar,l,t,r,b,ncol,nrow : byte);

.PA

Š      C           H           A           P           T           E          R

      ------------------------------------------------------------------------

     2






      THE WINDOWS AND MENUS, COMPLETE REFERENCE LOOKUP




      This chapter describes all the procedures and functions of Windows and

      Menus V1.0. For your convenience they are arranged alphabetically. Here

      is a sample layout so you can easily understand the format of the lookup

      Note that only the relevant sections are listed in each entry.



      ------------------------------------------------------------------------

      SAMPLE PROCEDURE()                                    SAMPLE PROCEDURE()

      ------------------------------------------------------------------------


      type and    : Sayes weather it is a Function or Procedure, and if it is

      level         high or low level; 

    High Level : All the high level functions and procedures

carry out full type and range checking on 

all parameters passed to them, they also

carry out other error checking and display

messages where required (see appendix A).

The user can use these without fear or favor.


    Low Level  : In general the low level functions and procs

do not carry out any type or range checking

on any parameters passed to them, nor do they 

initiate any other error checking or display

any messages to the user, this is because all

these low level routines are used within the 

Windows and Menus unit, by the high level 

routines, so there is no need, so if you do

want to dabble with a little more power and

get your hands dirty, you'll need to take a

little more care,or you may burn your fingers


    This section also gives a brief description of the funct-

    ion or procedure.


      Syntax      : This is how it should be used.


      Variables   : This tells you about each parameter in the function or

    procedure call in detail, and how it should be declared

    along with its type. It also tells you what that parameter 

    does, what it cannot do and any checking that is carried

    out on it. A functions return value is also described. 

.PA

Š      Tables      : This section, if present, will give some form of tabulated

    information, such as a colour table.


      Example     : This section provides the user with a full working example

    using the function or procedure in question. Alternatively

    it will, where appropriate, just give a code segment.


      Rules Notes

      Tips & Traps: As the section title suggests, this is where you will find

    any rules to be observed and also offers additional info

    on the function or procedure in the form of tips and traps

    This section is most important and should always be read 

    in detail. The example is also explained in this section.

.PA

Š












     WINDOWS AND MENUS FOR TURBO PASCAL

     ----------------||----------------

     WINDOWS FUNCTIONS REFERENCE SECTION

.PA

Š      ------------------------------------------------------------------------

      NEW_WIN()                                                      NEW_WIN()

      ------------------------------------------------------------------------


      Function    : Set up a new window structure and return the user a unique

      High Level    ID number for future reference to that particular window.

       The windows text cursor, used by the WWRITE(); and

    WWRITELN(); procedures only, is positioned at x1,y1 which

    is the top left corner of the window excluding the border

    the Winmen window text cursor can be positioned using the

    WGOTOXY(); procedure, it has no effect at all on the Turbo

    Pascal text cursor, which is used with the write(); and

    read(); procedures and positioned with gotoxy().

       This function is not called by any of the functions or

    procedures in the Winmen Unit.

       The windows record is created and updated to reflect

    any changes.


      Syntax      : ID := NEW_WIN(l,t,r,b,ty,bb,bf,tb,tf);


      Variables   : ID : byte;

    Receives the returned unique window identifier.


    l : byte; (B1_78)

    Leftmost edge of the window including border, must be a

    value between 1-78 or a range check error will occure.


    t : byte; (B1_23)

    Topmost edge of the window including border, must be a

    value between 1-23 or a range check error will occure.


    r : byte; (B3_80)

    Rightmost edge of the window including border, must be a

    value between 3-80 or a range check error will occure.


    b : byte; (B3_25)

    Bottommost edge of the window including border, must be a

    value between 3-25 or a range check error will occure.


    ty : byte; (B1_4)

    Type of border required around the window edge, must be a

    value between 1-4 or a range check error will occure.

    The possible border types are as follows:-

       1 = Double horizontal and double vertical bars.

       2 = Single horizontal and single vertical bars.

       3 = Double horizontal and single vertical bars.

       4 = Single horizontal and double vertical bars.


    bb : byte; (B0_15)

    Border background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).

.PA

Š     bf : byte; (B0_15)

    Border foregroung colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tb : byte; (B0_15)

    Text background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tf : byte; (B0_15)

    Text foreground colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


  CGA                    MDA

      Colour Table:            Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program NEW_WIND;

    uses dos,crt,winmen;

    var

       ID : byte;

    begin

       ID := NEW_WIN(5,5,50,20,1,1,14,7,0);

       WOPEN(ID);

       writeln(scr,'A window 46 cols x 16 rows');

       write(scr,'Press Return');

       readln;

       WMDELETE(ID);

       normvideo;

    end.

.PA

Š      Notes Rules

      Tips & Traps: A maximum of 255 unique identifiers can be allocated

    the first 20 (0-19) of these are used only for user

    saved screen areas using WMSAVE_SCR(), the rest 236

    (20-255) of these are to be shared between NEW_WIN()

    and NEW_MENU(), if all possible identifiers have been

    allocated or there is insuficient memory left for the

    window the programme will abort with an error message

    (see apendix for list), although you will most likely

    run out of memory before identifiers, depending upon

    the size of existing windows and menus.

    You can of course free up memory and unique identifiers

    by using WMDELETE() to delete unwanted windows or menus.

    Take care not to overwrite or lose the returned unique

    identifier ID as this is your only link with the

    window record structure and means of using/deleting the

    window.

    The window must be of a minimum size of 3 columns by 3

    rows else there would not be any display area, if it

    is less than this the programme will abort with an error

    message (see apendix for list).

    The function will always allocate a fixed amount of memory

    for the window record, but the amount of memory allocated

    for the screen under the window, of course depends upon

    the size of the window.

.PA

Š












     WINDOWS AND MENUS FOR TURBO PASCAL 

     ----------------||----------------

    WINDOWS PROCEDURES REFERENCE SECTION

.PA 49

Š      ------------------------------------------------------------------------

      WCLRSCR()                                                      WCLRSCR()

      ------------------------------------------------------------------------


      Procedure   : Clears the window or user screen area, (created with

      High Level    NEW_WIN() or WMSAVE_SCR()) associated with the unique

    identifier ID, to the text background colour defined in

    its record.

       This procedure interrogates the Winmen 3D screen MAP[]

    while it is operating, this allows it to clear the screen

    of windows and user screen that are partialy or even fully

    obscured by other objects, while still leaving the

    foreground intact, the ID_SC[] background screen array,

    of any obscuring objects, will be updated automatically.

    Windows and user screens not obscured by other objects

    can, of course, also be cleared.

       It will also clear windows and user screen that are not

    linked into the 3D screen MAP[] system, this could occure

    if an object has just been slid using the WMSLIDE();

    procedure and the user has not relinked the object into

    the 3D screen MAP[] using the WMADD_MREC_ALL(); procedure,

    refer to the WMSLIDE(); procedure for further details. If

    an unlinked object, that is obscured by other objects, is

    cleared, beware! the parts of the objects that are

    covering the window or user screen being cleared will be

    wiped from the screen, not being linked into the 3D screen

    MAP[] means the system does not know what is above or

    below the object in question.

       The window record is not affected by this command.


      Syntax      : WCLRSCR(ID);


      Variables   : ID : byte;

    The unique identifier for the specified window as returned

    from NEW_WIN() or a user screen area ID.

    If the ID does not exist or the ID belongs to a menu the

    programme will abort with an error message. (see apendix

    for list).  


      Example     : program WCLRSCRN;

    uses dos,crt,winmen;

    var

       ID : byte;

    begin

       ID := NEW_WIN(1,1,80,25,1,1,14,7,0);

       WOPEN(ID);

       writeln(scr,'A window 80 cols x 25 rows');

       write(scr,'Press Rerturn To Clear Window');

       readln;

.PA

Š        WCLRSCR(ID);   {*CLEARS TO COLOUR 7-WHITE*}

       write(scr,'Window Cleared, Press Return');

       readln;

       WDELETE(ID);

       normvideo;

    end.


      Rules Notes

      Tips & Traps: The text background colour, for a window, was originaly

    defined in the call to NEW_WIN(), unless it has since

    been changed using WCOLOUR() or WMATTRIBS().

       A user screen area when cleared using WCLRSCR() is

    cleared to the limits of l,t,r,b ie.  it is active right

    to its edges, unlike a window which is cleared up to its

    border ie. its only active to l+1,t+1,r-1,b-1 1 character

    less all round, this is to allow for the window border.

       When the user saves an area with WMSAVE_SCR()

    information put in the screen record apart from its bounds

    are, the text background and foreground colour values,

    which are taken from the TEXTATTR system variable at the

    time of saving, so whatever colours were active when

    WMSAVE_SCR() was called will be used each time the user

    saved screen area is cleared using WCLRSCR() or written to

    after selecting, using WSELECT().

       The colour values held in the window or user screen

    record can be changed using WCOLOUR() or WMATTRIBS(),

    these will update the record.

       WCLRSCR() has no effect on a closed window.

       Any open window or user screen area active or not

    active can be cleared.

       A window or user screen area when cleared will become

    the active one.

.PA

Š      ------------------------------------------------------------------------

      WCOLOUR()                                                      WCOLOUR()

      ------------------------------------------------------------------------


      Procedure   : Changes the text foreground and background colours of

      high Level    the window or user screen area, (created with NEW_WIN()

    or WMSAVE_SCR()) associated with the unique identifier

    ID, by updating its record.

    The window record is updated to reflect the changes.


      Syntax      : WCOLOUR(ID,tb,tf);


      Variables   : ID : byte;

    The unique identifier for the specified window as returned

    from NEW_WIN() or a user screen area ID.

    If the ID does not exist or the ID belongs to a menu the

    programme will abort with an error message. (see apendix

    for list).                                                


    tb : byte; (B0_15)

    Text background colour, must be a value in the range 0-15

    or a range check error will occure. (see colour table

    below).


    tf : byte; (B0_15)

    Text foreground colour, must be a value in the range 0-15

    or a range check error will occure. (see colour table

    below).


  CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program WIN_COLOUR;

    uses dos,crt,winmen;

    var

       ID : byte;

.PA

Š     begin

       ID := NEW_WIN(1,1,80,25,1,1,14,7,0);

       WOPEN(ID);

       writeln(scr,'A window 80 cols x 25 rows');

       write(scr,'Press Return To Change Colours');

       readln;

       WCOLOUR(ID,4,14);

       writeln(scr,'Colours Now Changed From Black on White');

       writeln(scr,'To Yellow on Red');

       write(scr,'Press Return To Clear To New Bkground');

       readln;

       WCLRSCR(ID);   {*CLEARS TO COLOUR 4-RED*}

       write(scr,'Press Return');

       readln;

       WMDELETE(ID);

       normvideo;

    end.


      Rules Notes

      Tips & Traps: The colour changes will take effect the next time the

    window or user saved screen is:-

    A) Written to, if it is already open and is the active

       one.

    B) Selected for use, with WSELECT() and written to

       regardless of weather it is open or closed as

       WSELECT() will open it and make it active.

    C) Opened for use, with WOPEN() and written to, as

       WOPEN() also selects it for use.

    Any window or user screen area, open, closed, active or

    not active can have its colours changed ready for the

    next time it is used, This can be most effective when

    used with WCLRSCR().

    If the window is closed or not active only the window

    record is updated.

    This procedure does not affect window/user screen area

    currency.

.PA

Š      ------------------------------------------------------------------------

      WEXPLODE()                                                    WEXPLODE()

      ------------------------------------------------------------------------


      Procedure   : Explode a box of the specified size, type and colour on to

      High Level    the screen at the same time clearing the background to

    the specified colour.

    No window records are affected by this command.


      Syntax      : WEXPLODE(l,t,r,b,btype,bb,bf,tb);


      Variables   : l : byte; (B1_78)

    Left edge of the box must be a value between 1-78 or a

    range check error will occure.


    t : byte; (B1_23)

    Top edge of the box must be a value between 1-23 or a

    range check error will occure.


    r : byte; (B3_80)

    Right edge of the box must be a value between 3-80 or a

    range check error will occure.


    b : byte; (B3_25)

    Bottom edge of the box must be a value between 3-25 or a

    range check error will occure.


    btype : byte; (B1_4)

    Type of box required must be a value between 1-4 or a

    range check error will occure. The possible border types

    are as follows:-

       1 = Double horizontal and double vertical bars.

       2 = Single horizontal and single vertical bars.

       3 = Double horizontal and single vertical bars.

       4 = Single horizontal and double vertical bars.


    bb : byte; (B0_15)

    Border background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    bf : byte; (B0_15)

    Border foregroung colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tb : byte; (B0_15)

    Colour to clear background to (text background colour),

    must be a value in the range 0-15 or a range check error

    will occure. (see colour table below).

.PA

Š   CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program EXPLODE;

    uses dos,crt,winmen;

    begin

       clrscr;

       WEXPLODE(1,1,80,25,3,2,14,0);

       gotoxy(25,10);

       write(scr,'Press Return For Another Explode');

       readln;

       WEXPLODE(5,5,75,20,3,1,2,0);

       gotoxy(25,10);

       write(scr,'Press Return');

       readln;

       normvideo;

       clrscr;

    end.


      Rules Notes

      Tips & Traps: The above example will explode a box to fill the complete

    screen, the box type will be Double horizontal and single

    vertical bars, with a border background colour of green

    and foreground colour of yellow, it will be cleared to

    black.

    The resulting box must be a minimum size of 3x3 chars

    else a box cannot be drawn and the programme will abort

    with an error message (see apendix for list).

    The second example would just clear the screen from the

    centre outwards (explode), as the border background,

    foreground and clearing colour values are all the same.

.PA

Š      ------------------------------------------------------------------------

      WGOTOXY()                                                      WGOTOXY()

      ------------------------------------------------------------------------ 


      Procedure   : This procedure positions the text cursor, for the window 

      High Level    or user screen (ID < 20) specified by ID, at the 

    location given in the x,y parameters.

       Location 1,1 in any window or user screen is the top 

    left corner of the object, excluding the border, if its 

    a window.   

       This procedure only positions the cursor that is used

    when the WWRITELN(); and WWRITE(); procedures are used, it

    does this by setting the wmrec fields ".x" and ".y" to the

    values supplied in the WGOTOXY(); procedure.

       This procedure does not affect the normal text cursor

    position, associated with the writeln(); write();

    readln(); read(); and gotoxy() standard procedures.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       The objects wmrec is updated by this procedure.

       This procedure is not called by any functions or

    procedures in the Winmen Unit.

       The ".x" and ".y" cursor position, for the specified

    window, will be set and updated in wmrec, regardless of

    weather the window, or user screen is active, open or

    closed.

      

      Syntax      : WGOTOXY(ID,x,y);


      Variables   : ID : byte;

    The unique identifier for the specified window or user 

    saved screen area, as returned from NEW_WIN() and as sent 

    to WMSAVE_SCR(0-19), if it is a user saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).


    x : byte;

    This is the column at which to position the cursor in

    the window or user screen specified by ID.

       This value must be in the range 1 - (".r"-".l"-1) for a

    window or 1 - (".r"-".l"+1) for a user screen (ID < 20),

    i.e. it must not be greater than the total number of

    columns, less 2 for the boarder, in a window and not

    greater than the total number of columns in a user screen,

    as there is no boarder.

       If the x value supplied is outside the ranges given 

    above, then the cursor position will be left unaltered. 

.PA

Š     y : byte;

    This is the column at which to position the cursor in

    the window or user screen specified by ID.

       This value must be in the range 1 - (".b"-".t"-1) for a

    window or 1 - (".b"-".t"+1) for a user screen (ID < 20),

    i.e. it must not be greater than the total number of

    columns, less 2 for the boarder, in a window and not

    greater than the total number of columns in a user screen,

    as there is no boarder.                                    

       If the y value supplied is outside the ranges given 

    above, then the cursor position will be left unaltered.    


      Example     : program WGOTO_XY;


    uses crt,dos,winmen;


    var

       w1 : byte;


    begin                             {*CREATE WINDOW*}

       clrscr;

       textbackground(0);

       textcolor(7);

       w1 := NEW_WIN(8,8,50,20,1,4,14,1,14);      

       WOPEN(w1);                     {*OPEN IT*}            

       WWRITE(w1,'Text Positioned At 1,1 <RET> To Cont....');

       readln;                        {*WRITE & WAIT RETURN*}  

       WGOTOXY(w1,10,4);              {*REPOSITION CURSOR*}    

       WWRITE(w1,'Text At 10,4 <RET>....');         

       readln;                        {*WRITE & WAIT RETURN*}                 

       WGOTOXY(w1,19,10);             {*REPOSITION CURSOR*}    

       WWRITE(w1,'Text At 19,10 <RET>....');        

       readln;                        {*WRITE & WAIT RETURN*}

    end.


      Rules Notes

      Tips & Traps: There are no special rules to be observed when using 

    this procedure, other than those outlined above.

       The example being demonstrative and straightforward 

    requires no explanation and is left to the user to 

    examine.   

.PA

Š      ------------------------------------------------------------------------

      WOPEN()                                                          WOPEN()

      ------------------------------------------------------------------------


      Procedure   : Opens the window, or user screen (ID < 20), associated

      High Level    with the unique identifier ID, previously created using

    NEW_WIN(); for windows or WMSAVE_SCR(); for user screens,

    user screens are open by default as soon as the

    WMSAVE_SCR(); procedure is called with an ID < 20, but may

    be closed with the WMCLOSE(); procedure.

       Windows are opened by exploding them on to the screen,

    while user screens are opened by placing them on the

    screen, this is because user screens have no border.

       Windows are opened with a completely clear screen area,

    but when user screens are opened, whatever is in there

    ID_SC[] background screen array will be displayed on the

    screen. This old ID_SC[] background image is then

    overwritten with the new area under the user screen, which

    was saved into a temporary area automaticaly, this is

    another reason why user screens cannot be exploded onto

    the screen.

       The area of screen under the window or user screen is

    saved away in the objects ID_SC[] background screen

    array and the object is linked into the 3D screen MAP[]

    system, see the WMSAVE_SCR(); procedure and the "maprec"

    type definition, which is in the section "Winmen

    Declared Types", for full information on this subject.

       This routine is also called by WSELECT(); it may also

    be called by one of the following routines, through

    WSELECT(); depending on certain factors, see individual

    routines for full details:- WWRITE(); WWRITELN();

    WMFLOAT(); WMMOVE(); WMSLIDE(); and WMTITLE();

       The window or user screen (ID < 20) record is updated

    to reflect anye changes.


      Syntax      : WOPEN(ID);


      Variables   : ID : byte;

    The unique identifier for the specified window or user

    screen as returned from NEW_WIN() or sent to WMSAVE_SCR();

    if its a user screen.

       If the ID does not exist or the ID belongs to a menu

    the programme will abort with an error message.  (see

    apendix for list).


      Example     : program WOPEN_WIN;

    uses dos,crt,winmen;

    var

       ID : byte;

.PA

Š     begin

       clrscr;

       ID := NEW_WIN(10,5,55,20,1,1,2,3,4);

       gotoxy(10,15);

       write(scr,'Press Return To Open A Window');

       readln;

       WOPEN(ID);

       write(scr,'Press return To Reveal Previous Message');

       readln;

       WMDELETE(ID);

       gotoxy(39,15);

       readln;

       normvideo;

       clrscr;

    end.


      Rules Notes

      Tips & Traps: The bounds and attributes of the window were set in the

    call to NEW_WIN()

    The call to WOPEN() will be ignored if the window is

    already open or the ID belongs to a user screen area.

    (user screen areas effectively have nothing to open

    as they have no border).

    The screen area under the window is preserved and restored

    when the window is closed.

    The window ID is now the active one and can be written to

    cleared read from etc.

.PA

Š      ------------------------------------------------------------------------

      WSELECT()                                                      WSELECT()

      ------------------------------------------------------------------------


      Procedure   : Select the window or user screen area, created with

      High Level    NEW_WIN() or WMSAVE_SCR() and associated with the unique

    identifier ID for use, if it is closed it will be opened,

    refer to the WOPEN(); procedure for more information.

       The window or user screen (ID<20) record is updated to

    reflect any changes.

       This routine is also called by the following routines,

    depending on certain factors, see individual routines for

    full details:- WWRITE(); WWRITELN(); WMFLOAT(); WMMOVE();

    WMSLIDE(); and WMTITLE().

       The WSELECT(); procedure is one of the only routines

    that does not call WMFLOAT(); out of all the routines that

    may need to do so.

       The reasons for this are as follows:-

       You may want to write to more than one window at once,

    or at least, make it appear as if you are.  This can only

    be done by first selecting the window to write to, using

    WSELECT(); then actualy writing to it.  If the WSELECT();

    procedure had to call WMFLOAT() each time it was called,

    this would slow things down considerably and spoil our

    illusion, besides the windows that you are writing to may

    all be fully visible, in which case there is no need to

    float them to the surface before writing to them.  if they

    are obscured and you dont want to make use of the

    WWRITE(); or WWRITELN(); procedures, to write text to a

    window in the background, then you will have to call

    WMFLOAT(); either before or after calling WSELECT(); and

    prior to writing to each window.  So as you can see the

    choice is best left up to the user, for maximum

    flexibility.


      Syntax      : WSELECT(ID);


      Variables   : ID : byte;

    The unique identifier for the specified window or user

    screen as returned from NEW_WIN() or sent to WMSAVE_SCR();

    if its a user screen.

       If the ID does not exist or the ID belongs to a menu

    the programme will abort with an error message.  (see

    apendix for list).

.PA

Š      Example     : program WSELECT;

    uses dos,crt,winmen;

    var

       ID : byte;

    begin

       clrscr;

       ID := NEW_WIN(5,6,60,10,4,1,2,3,4);

       gotoxy(5,5);

       write(scr,'Press return To Open & Select The Window');

       readln;

       WSELECT(ID);     *{OPEN THE NEWLY CREATED WINDOW}*

*{AND SELECT IT FOR USE        }*

       writeln(scr,'Theres No Need To Use Wopen & Wselect');

       write(scr,'One Or the Other Will Do. Press Return');

       readln;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: Makes the chosen window or user screen area ID the active

    one. (selects it for use, for writing to etc).

       If the window or user screen is closed it will be

    opened, refer to the WOPEN(); procedure for further info.

       For a user screen area the background and forground

    text colours used for writing/clearing will be the ones

    saved from the TEXTATTR system variable when the user

    screen was created, unless previously changed via

    WCOLOUR() or WMATTRIBS(), as opposed to the preselected

    colours chosen via NEW_WIN() for a window.

       A user screen area will always require selecting if it

    is to be used directly after creating with WMSAVE_SCR(),

    as that procedure does not change the currency of a user

    screen area or window, ie. WMSAVE_SCR() does not make an

    ID the active one.

       The procedure will halt the programme if an attempt is

    made to select a window or user screen area which does not

    yet exist, an error message will be displayed (see apendix

    for list).

.PA

Š      ------------------------------------------------------------------------

      WWRITE()                                                        WWRITE()

      ------------------------------------------------------------------------ 


      Procedure   : This procedure enables the user to write a text string 

      High Level    "stg" to any window, or user screen (ID < 20). 

       The window or user screen can be written to even if it 

    is partialy or even totaly obscured by other objects (in 

    background).

       The background screen arrays of any obscuring objects 

    are automaticaly updated with the new or changed 

    information, so that when any obscuring objects are 

    removed from view the contents of the window or user 

    screen, that was written to, is visualy correct.

       Any text written to a part of a window or user screen 

    that is obscured, by other object(s), will not become 

    visible until the obscuring object(s) are either removed 

    from the display, moved, or slid away, or the window or 

    user screen that was written to is floated to the 

    surface.   

       If the window or user screen, specified by ID, is found 

    to be closed, it is opened for use, and will be the active 

    one after writing is completed. This is most important, 

    as the WOPEN() procedure, which is called if it is closed, 

    will ensure that the window or user screen in question is 

    properly linked into the 3D screen map, on which the 

    WWRITE() procedure relies for correct operation. (see 

    also the _WSCROLL_UP() procedure for more detailed 

    information on this subject).   

       If it is already open for use, its currency is left 

    unaltered, i.e. if it was open but not the active one, it 

    will remain non-active and if it was the active one, it 

    will remain the active one.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       The objects "wmrec" fields ".x" and ".y" are updated by

    this procedure, to reflect the continually changing

    position of the cursor in the window, specified by ID, as

    the text string "stg" is written. This also allows the

    user to determine the position of the Winmen text cursor

    within any window or user screen, prior to writing, for     more detail on the "wmrec" type and its fields, refer to

    the section "Winmen Declared Types".

       Text output can be directed to any location within the

    window or user screen specified by ID, by repositioning

    the Winmen text cursor with the WGOTOXY() procedure, this

    has no effect at all on the Turbo Pascal text cursor,

    which is used with the standard write(); writeln()

    read() ; readln() and gotoxy() procedures.

       The WWRITE() procedure has no connection with the

    standard Turbo Pascal write() procedure.

       This procedure is called by:- WWRITELN();

.PA

Š      Syntax      : WWRITE(ID,stg);


      Variables   : ID : byte;

    The unique identifier for the specified window or user 

    saved screen area, as returned from NEW_WIN() and as sent 

    to WMSAVE_SCR(0-19), if it is a user saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).             


    stg : string;

                    This is the ascii text string that will be printed in the

    window or user screen, specified by ID.

       The string can be up to 255 characters in length, any

    longer and Turbo Pascal will issue a range check error,

    which will termminate the programe.

       The string can contain any valid ascii character in the

    range 0-255, although any control characters present in

    the "stg" string arguement will be printed, unlike the

    standard write() procedure, which acts on them, i.e.

    chr(7) would be printed as '' by WWRITE(); but write()

    would sound the bell. WWRITE() will print all characters.

                       The WWRITE() procedure only takes a single string as

                    its arguement, rather than a complete arguement list, as

                    in the standard write() procedure. What this means is

                    that the user will have to convert any non-ascii text

                    variables to a text string first and then consatenate

                    all the required arguements in to one string, prior to

                    using the WWRITE() procedure.

                       The WWRITE() procedure will automaticaly wrap the text

    onto the next line when the cursor reaches the righmost

    edge of the current line, for the window or user screen

    specified by ID. 

       If the last character to be written is the last 

    character on a line, then the next time that window or 

    user screen is written to using WWRITE(); or WWRITELN(); 

    writing will automaticaly start at the begining of the 

    next line.

       If the last character to be written is the last 

    character on the last line, then the next time that window 

    or user screen is written to the contents of it will 

    automaticaly be scrolled up one line, leaving the new 

    bottom line blank.  Writting will then commence at the 

    start of this new bottom line.

       The WWRITE() procedure will automaticaly scroll the 

    entire contents, of the window or user screen, up by one 

    line, when the text exceeds the rightmost character on the 

    bottommost line.

       The WWRITE() procedure always leaves the Winmen text

    cursor at the next available blank character within the

    current window or user screen, ready for the next write.

.PA

Š      Example     : program W_WRITE;   

    uses dos,crt,winmen;                                      

    var

       w1,w2,win : byte;

       ch : char;

       c : word;

    begin                             {*DEFINE WINDOWS*}

       w1 := NEW_WIN(5,5,40,15,1,1,2,0,14);

       w2 := NEW_WIN(20,8,65,18,2,5,6,7,0);

       WOPEN(w1);                     {*OPEN THEM*}

       WOPEN(w2);

       for c := 1 to 3000 do          {*WRITE CHARACTERS*}

       begin                          {*RANDOMLY TO WINDOWS*}

  win := 0;

  while not(win in[w1,w2]) do

  win := random(w2+2);

  ch := chr(random(255));

  WWRITE(win,ch);

       end;

       WMFLOAT(w1);                   {*FLOAT 'EM ABOUT*}

       delay(1500);

       WMFLOAT(w2);

       delay(1500);

       WMDELETE(w1);

       delay(1000);

       WMDELETE(w2);                  {*DELETE 'EM*}

    end.


      Rules Notes

      Tips & Traps: There are no additional, special rules or tips to follow 

    for this procedure, other than those outlined in the 

    preceeding paragraphs above. 

       The example being demonstrative and straightforward 

    requires no explanation and is left to the user to 

    examine.  

.PA

Š      ------------------------------------------------------------------------

      WWRITELN()                                                    WWRITELN() 

      ------------------------------------------------------------------------ 


      Procedure   : This procedure enables the user to write a text string 

      High Level    "stg" to any window, or user screen (ID < 20). 

       The window or user screen can be written to even if it 

    is partialy or even totaly obscured by other objects (in 

    background).

       The background screen arrays of any obscuring objects 

    are automaticaly updated with the new or changed 

    information, so that when any obscuring objects are 

    removed from view the contents of the window or user 

    screen, that was written to, is visualy correct.

       Any text written to a part of a window or user screen 

    that is obscured, by other object(s), will not become 

    visible until the obscuring object(s) are either removed 

    from the display, moved, or slid away, or the window or 

    user screen that was written to is floated to the 

    surface.   

       If the window or user screen, specified by ID, is found 

    to be closed, it is opened for use, and will be the active 

    one after writing is completed. This is most important, 

    as the WOPEN() procedure, which is called if it is closed, 

    will ensure that the window or user screen in question is 

    properly linked into the 3D screen map, on which the 

    WWRITELN() procedure relies for correct operation. (see 

    also the _WSCROLL_UP() procedure for more detailed 

    information on this subject).   

       If it is already open for use, its currency is left 

    unaltered, i.e. if it was open but not the active one, it 

    will remain non-active and if it was the active one, it 

    will remain the active one.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       The objects "wmrec" fields ".x" and ".y" are updated by

    this procedure, to reflect the continually changing

    position of the cursor in the window, specified by ID, as

    the text string "stg" is written. This also allows the

    user to determine the position of the Winmen text cursor

    within any window or user screen, prior to writing, for

    more detail on the "wmrec" type and its fields, refer to

    the section "Winmen Declared Types".

       Text output can be directed to any location within the

    window or user screen specified by ID, by repositioning

    the Winmen text cursor with the WGOTOXY() procedure, this

    has no effect at all on the Turbo Pascal text cursor,

    which is used with the standard write(); writeln()

    read() ; readln() and gotoxy() procedures.

       The WWRITELN() procedure has no connection with the

    standard Turbo Pascal writeln() procedure.

       This procedure is not called by ony of the functions 

    or procedures in the Winmen Unit. 

.PA

Š      Syntax      : WWRITELN(ID,stg);


      Variables   : ID : byte;

    The unique identifier for the specified window or user 

    saved screen area, as returned from NEW_WIN() and as sent 

    to WMSAVE_SCR(0-19), if it is a user saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).             


    stg : string;

    This is the ascii text string that will be printed in the

    window or user screen, specified by ID.

       The string can be up to 255 characters in length, any

    longer and Turbo Pascal will issue a range check error,

    which will termminate the programe.

       The string can contain any valid ascii character in the 

    range 0-255, although any control characters present in 

    the "stg" string arguement will be printed, unlike the 

    standard writeln() procedure, which acts on them, i.e.  

    chr(7) would be printed as '' by WWRITELN(); but 

    writeln() would sound the bell.  WWRITELN() will print all 

    characters.

       The WWRITELN() procedure only takes a single string as 

    its arguement, rather than a complete arguement list, as 

    in the standard writeln() procedure.  What this means is 

    that the user will have to convert any non-ascii text 

    variables to a text string first and then consatenate all 

    the required arguements in to one string, prior to using 

    the WWRITELN() procedure.

       The WWRITELN() procedure will automaticaly wrap the 

    text onto the next line when the cursor reaches the 

    righmost edge of the current line, for the window or user 

    screen specified by ID.

       The WWRITE() procedure will automaticaly scroll the 

    entire contents, of the window or user screen, up by one 

    line, when the text exceeds the rightmost character on the 

    bottommost line.

       Regardless of where, on a line, writing ends, the

    Winmen text cursor will always be advanced to the start of

    the next line, so that the next time that window or user

    screen is written to using WWRITELN(); or WWRITE();

    writing will automaticaly start at the begining of that

    line, in otherwords a carriage return and line feed are

    always the last operations to be carried out by

    WWRITELN();


      Example     : program W_WRITELN;

    uses dos,crt,winmen;

.PA

Š     var

       w1,w2,win,n,max : byte;

       ch : string[60];

       c : word;


    begin

       textbackground(0);

       clrscr;                        {*DEFINE WINDOWS*}

       w1 := NEW_WIN(5,5,40,15,1,1,2,0,14);

       w2 := NEW_WIN(20,8,65,18,2,5,6,7,0);

       WOPEN(w1);                     {*OPEN THEM*}

       WOPEN(w2);

       delay(1500);

       for c := 1 to 400 do           {*WRITE CHARACTERS*}

       begin                          {*RANDOMLY TO WINDOWS*}

  win := 0;

  while not(win in[w1,w2]) do

     win := random(w2+2);

  max := 0;

  while not(max in[1..50]) do

     max := random(55);

  ch := '';

  for n := 1 to max do

     ch := ch+chr(random(255));

  WWRITELN(win,ch);

       end;

       WMFLOAT(w1);                   {*FLOAT 'EM ABOUT*}

       delay(1500);

       WMFLOAT(w2);

       delay(1500);

       WMDELETE(w1);

       delay(1000);

       WMDELETE(w2);                  {*DELETE 'EM*}

    end.


      Rules Notes

      Tips & Traps: There are no additional, special rules or tips to follow 

    for this procedure, other than those outlined in the 

    preceeding paragraphs above. 

       The example being demonstrative and straightforward 

    requires no explanation and is left to the user to 

    examine.                                                   

.PA

Š      ------------------------------------------------------------------------

      _WBOX_ON()                                                    _WBOX_ON()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by WOPEN() and WEXPLODE(), used

      Low Level     to display a box on the screen at the specified position,

    using the combined byte attributes for character type and

    colour, to form a screen ram word value, which specifies

    the character and colour to be put directly into screen

    ram for the horizontal, vertical and four box corner

    characters.

    No window records are affected by this command.

    No checks are carried out on the validity of data supplied 

    to this low level procedure, so extra care is required.


      Syntax      : _WBOX_ON(l,t,r,b,tlc,trc,blc,brc,horc,verc);


      Variables   : l : byte; (B1_80)

    Leftmost edge of the box including border, must be a

    value between 1-80 or a range check error will occure.


    t : byte; (B1_25)

    Topmost edge of the box including border, must be a

    value between 1-25 or a range check error will occure.


    r : byte; (B1_80)

    Rightmost edge of the box including border, must be a

    value between 1-80 or a range check error will occure.


    b : byte; (B1_25)

    Bottommost edge of the box including border, must be a

    value between 1-25 or a range check error will occure.


    tlc : word;

    Word attribute value for the top left corner character

    of the box.


    trc : word;

    Word attribute value for the top right corner character

    of the box.


    blc : word;

    Word attribute value for the bottom left corner character

    of the box.


    brc : word;

    Word attribute value for the bottom right corner character

    of the box.


    horc : word;

    Word attribute value for all the horizontal characters of

    the box.

.PA

Š





                          PAGE 68 TO BE PRINTED HERE






.PA

Š      Example     : program _WBOX_ON;

    uses dos,crt,winmen;

    var

       tlc,trc,blc,brc,horc,verc,colour : word;

    begin

       colour := (7 shl 4) + 12;     {*BK WHITE + FG LRED*}

       tlc := (colour shl 8) + 201   {*I*}

       trc := (colour shl 8) + 187;       {*;*}

       blc := (colour shl 8) + 200;  {*H*}

       brc := (colour shl 8) + 188;       {*<*}

       horc := (colour shl 8) + 205; {*M*}

       verc := (colour shl 8) + 186;      {*:*}

       clrscr;

       _WBOX_ON(1,1,80,25,tlc,trc,blc,brc,horc,verc);

       gotoxy(25,10);

       write(scr,'Press Return To Draw Box Off');

       readln;

       _WBOX_ON(1,1,80,25,0,0,0,0,0,0);

       gotoxy(25,11);

       write(scr,'Press Return');

       readln;

       normvideo;

       clrscr;

    end.


      Rules Notes

      Tips & Traps: This procedure calculates the screen ram offsets using

    the values supplied for l,t,r,b of the box and places

    the given screen ram character/colour attribute words,

    directly in the calculated screen addresses, This makes

    this procedure extremely fast at drawing boxes, which it

    needs to be, to enable it to be used during the WOPEN()

    and WEXPLODE() procedures.

    The example will draw a box to outline the screen, the

    border will be double horizontal and double vertical

    lines, the background colour will be white while the

    foreground colour will be light red.

    Notice the technique for constructing the colour value,

    although the actual colour only occupies a byte, in this

    case the colour variable must be a word value, this is

    because it is shifted left 8 bits when we come to make

    up the character/colour screen attribute word,

    tlc := (colour shl 8) + 201, if a byte were used in this

    instance, shifting it left 8 bits would effectively zero

    the colour variable, as the brackets are done first and

    this operation is done using the variable colour as

    opposed to variable tbc which is a word.

    So the screen ram attribute word is made by shifting the

    colour attribute value into the high order byte and

    adding to it the ASCII character value (low byte),

    not forgetting that this is actualy the reverse of how

    it would be found in screen ram because of DOS.

.PA

Š     The example then effectively draws the box off, by

    sending a zero values (bkground colour black, fground

    colour not care, character value null) to the _WBOX_ON()

    procedure, this of course assumes that the screen was

    black to start with, if it were not then the appropriate

    bkground colour along with any value (0-15) for fground

    colour and null for the character value must be combined

    as before and sent as the screen attribute word to have

    this effect.

.PA

Š      ------------------------------------------------------------------------

      _WCHK_MIN_SIZE()                                        _WCHK_MIN_SIZE()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by NEW_WIN() and WEXPLODE()

      Low Level     used to check that the box/window size is a minimum of

    3x3 characters

    No window records are affected by this command.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _WCHK_MIN_SIZE(proc,l,t,r,b);


      Variables   : proc : string;

    This string should be the name of the function or procedure

    that is calling the _WCHK_MIN_SIZE() procedure, i.e. if say

    a procedure called MYPR() were to call _WCHK_MIN_SIZE()

    the format should be as follows _WCHK_MIN_SIZE(IDB,'MYPR');

    Although of course in reality you could use any string you

    want up to a maximum of 255 characters.

    If the string is longer than 255 characters a range check

    error will occure.                                        

    MYPR will be the routine name displayed in the error 

    message should the check fail. 


    l : byte; (B1_78)

    Leftmost edge of the window/box including border, must be

    a value between 1-78 or a range check error will occure.


    t : byte; (B1_23)

    Topmost edge of the window/box including border, must be

    a value between 1-23 or a range check error will occure.


    r : byte; (B3_80)

    Rightmost edge of the window/box including border, must be

    a value between 3-80 or a range check error will occure.


    b : byte; (B3_25)

    Bottommost edge of the window/box including border, must

    be a value between 3-25 or a range check error will

    occure.

.PA

Š      Example     : procedure SOME_WINDOW_PROC(l,t,r,b,x,y,z : byte);

    var

      .......etc;

    begin

       _WCHK_MIN_SIZE('SOME_WINDOW_PROC',l,t,r,b);

       remainder

  of code executed

     if box size was >= 3x3 chars

       else the _WCHK_MIN_SIZE() proc

  aborts programme with

     an error message

    end;


      Rules Notes

      Tips & Traps: A box of less than 3x3 characters cannot be displayed

    as there needs to be at laest 1 char in the middle of

    the box, for the box to have some purpose.

.PA

Š      ------------------------------------------------------------------------

      _WSCROLL_UP()                                              _WSCROLL_UP()

      ------------------------------------------------------------------------ 


      Procedure   : This procedure scrolls the entire contents of a window

      Low Level     or user screen (ID < 20) upwards by one line, the window 

    or user screen can be in the foreground or background.  

       The contents can be scrolled even if the window is 

    partialy or even totaly obscured by other objects (in 

    background). 

       The background screen arrays of any obscuring objects 

    are automaticaly updated with the new or changed 

    information, so that when any obscuring objects are 

    removed from view the contents of the scrolled window 

    is visualy correct.  

       The contents is scrolled up regardless of where in the 

    window the cursor is positioned, prior to calling the 

    _WSCROLL_UP() procedure.

       When the scroll is complete the cursor will be 

    positioned at column 1 on the last row of the window, 

    this last row will be blank, ready for writing to.

       This routine assumes that a maprec will be present in 

    the 3D screen map, for the given object and any obscuring 

    objects, at each character cell location covered by the 

    window being scrolled, if one does not the routine will 

    hang the system.  See the section on "Winmen Declared 

    Types" for information on the "maprec" record type.

       The 3D screen map is fundamental to the correct 

    operation of this very complex routine. 

       The user must make sure that the window or user 

    screen is actualy open, as no checks are carried out by 

    this low level procedure. If it is not open, then the 

    object is not linked into the 3D screen map, 

    consequently this procedure will cause the system to 

    hang or at best you will get a very messy screen.          

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().

       In keeping with all low level routines in the Windows 

    and Menus Unit, no checks are carried out on the validity 

    of data supplied to, or used by, this low level procedure, 

    so extra care is needed.  This is to prevent all the 

    checking and safety routines present in the Unit being 

    called more than once, as they are already called by all 

    the high level routines, there is no need, from the 

    Units point of view, to call them again in the low level 

    routines, as all the Units low level routines are always 

    called from a high level routine. A low level routine is 

    never called on its own, by the Unit, but the user may 

    of course do this, thats why the extra care is required. 

    For the Unit to carry out all its checking more than once 

    would be time consuming and unnecassary.

       The objects wmrec is not affected by this procedure.        

       This procedure is called by:- WWRITELN(); WWRITE();       

.PA

Š      Syntax      : _WSCROLL_UP(ID);


      Variables   : ID : byte;

    The unique identifier for the specified window or user 

    saved screen area, as returned from NEW_WIN() and as sent 

    to WMSAVE_SCR(0-19), if it is a user saved screen area.

       If the ID does not yet exist the results will be 

    unpredictable, as the ID is not checked. 


      Example     : program _WSCROLL;

    uses dos,crt,winmen;

    var

       w1,w2,w3,w,t : byte;

    begin

       clrscr;                        {*CREATE WINDOWS*}

       w1 := NEW_WIN(5,5,40,15,1,1,2,0,14);

       w2 := NEW_WIN(10,8,55,18,2,5,6,7,0);

       w3 := NEW_WIN(1,12,60,21,3,3,4,1,14);

       for w := w1 to w3 do           {*PUT SOME TEXT IN*}

       begin                          {*THE WINDOWS     *}

  WOPEN(w);

  for t := 1 to 5 do

  begin

     writeln('Some text to scroll up the window');

     writeln('Window the up scroll to text some');

     delay(350);

  end;

       end;

       window(1,1,80,25);             {*PUT UP MESSAGE*}

       gotoxy(26,23);

       textbackground(black);

       textcolor(yellow+blink);         

       write(chr(7),'*****SCROLLING TEXT NOW*****',chr(7));

       delay(1000);

       for w := 1 to 5 do             {*SCROLL UP TEXT IN*}

       begin                          {*WINDOWS          *}

  for t := w1 to w3 do

     _WSCROLL_UP(t);

  delay(500);

       end;

       for w := w1 to w3 do           {*DELETE ALL WINDOWS*}

       begin

  delay(750);

  WMDELETE(w);

       end;

    end.

.PA

Š      Rules Notes

      Tips & Traps: As you can see from the example the _WSCROLL_UP(); 

    procedure is very fast, we have had to put in some 

    delay() procedures to slow things down, so that you can 

    see what is happening. In fact its so fast that when you 

    scroll the contents of several windows in sucession, it 

    appears as if they are being scrolled simultainiously.  

       You could conceivably use this procedure to scroll up 

    the contents only, of a menu as well, although I can not 

    think of a reason why any one would want to do this. 

    Perhaps you may want to scroll the contents of the menu 

    untill it is completly clear and then write to it, using 

    the WWRITELN() or WWRITE() procedures, to temporarily 

    turn it into a window! now there's a thought.     

.PA

Š












     WINDOWS AND MENUS FOR TURBO PASCAL

     ----------------||----------------

      MENUS FUNCTIONS REFERENCE SECTION

.PA

Š      ------------------------------------------------------------------------

      BAR_MENU()                                                    BAR_MENU()

      ------------------------------------------------------------------------


      Function    : Display a menu, previously created using NEW_MENU(), in

      High Level    Bar Menu format, whose unique identifier is ID, at the

    specified row and column position, the menu will be "len"

    columns wide.

       The area of screen under the menu is saved away in the

    objects ID_SC[] background screen array and the menu is

    linked into the Winmen 3D screen MAP[] system automaticaly

    for full details on this subject refer to the

    WMSAVE_SCR(); procedure and the "maprec" record type,

    which is described in the section "Winmen Declared Types".

       There is also a system switch that affects the way in

    which the BAR_MENU(); function behaves:-


    1) MENU_ACT_ON_PC := true; Menu functions will return the

       number of the option chosen using the first character

       method.  Don't forget if there is more than one option

       with the same first character, it is the number of the

       first one in the list that will be returned.

       MENU_ACT_ON_PC := false; Menu functions will not return

       the number of the option chosen using the first

       character method.

       MENU_ACT_ON_PC := true; Default.


       The highlighted menu bar will always go to the option

    chosen, when the first character methos of option

    selection is used, regardles of how the switch is set.

       For more detail on this switch refer to the relevant

    section in the section "Winmen Declared Global Variables".

       A menu, when opened for the first time, will have its

    highlighted option bar placed on option 1, for each

    subsequent open, of that particular menu, the highlighted

    menu bar will appear on whatever menu option it was on,

    the last time the menu was closed. This feature applies

    to all menu types and also to the WMSLIDE(); WMMOVE(); and

    WMFLOAT(); procedures.

       The menu record is continually updated to reflect

    changes while the menu is active.

       This function is not called by any of the functions

    or procedures in the Winmen Unit.


      Syntax      : mc1 := BAR_MENU(ID,l,t,len);


      Variables   : mc1 : word (W1_400);

    This variable will receive the number of the option

    chosen on the Bar Menu. One is returned if the leftmost

    option is chosen, two for the next option and so on.

       A zero is returned if the Bar Menu is exited from, by

    pressing the escape key, without an option being chosen.

       A particular Bar Menu has to be the active one, ie.

    open and currently being used, to return an option number.

.PA

Š     ID : byte;

    The uniqueidentifier for the specified menu as returned

    from NEW_MENU().

       If the ID does not exist or the ID belongs to a window

    the programme will abort with an error message. (see

    apendix for list).


    l : byte; (B1_78)

    The column in which the leftmost edge of the Bar Menu is

    to be placed. Must be a value in the range 1-78 or a range

    check error will occure.


    t : byte; (B1_23)

    The row in which the top of the Bar Menu is to be placed.

    Must be a value in the range 1_23 or a range check error

    will occure.


    blen : byte; (B1_80)

    This is the length that the Bar Menu is to be drawn on the

    screen in columns. Must be a value in the range 1-80 or a

    range check error will occure.


      Example     : program BAR_MEN;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;


    begin

       getmem(mt,3*81);            {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Menu Option 1';  {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';  {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);           {*RECLAIM MEMORY AND  *}

       m1c := 10;                  {*DELETE POINTER TO IT*}

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,51);

  case m1c of

     1..3 : begin

       gotoxy(5,8);

       write('Menu Choice ',m1c,' Selected');

    end;

  end;

       end;

       normvideo;

    end.

.PA

Š      Rules Notes

      Tips & Traps: This function not only positions and displays the Bar

    Menu on the screen, but also handles all the highlighting

    and selection process and returns the number of the

    option chosen to the user, one being the leftmost option.

       If the menu is already open, only the selection process

    is carried out, ie. if the Bar Menu was used previously

    and exited without closing, the next time that particular

    open but non active Bar Menu is called, the function

    knows not to bother reopening the menu, but to go straight

    into the selection process, this saves a great deal of

    time and looks much nicer.

       The example programme will display a Bar Menu with

    three options, each option text is 13 characters in

    length, the length chosen for the Bar Menu is 51 columns,

    this leaves enough for a gap of 3 characters between

    options and at the start and end, (51-(13*3)) div 4 = 3,

    This formula can be used for calculating the Bar Menu

    length:- blen := sum of all option texts+(gap*(number

    options+1)); If the remainder of (blen-sum_opt) is not

    equaly divisable (in integer terms) by the (num_opt+1)

    then the quotiant is used for the gap and the integer

    remainder is added to the end gap.

       A Bar Menu is closed and exited by pressing the escape

    key while that menu is the active one, this forces a call

    to WMCLOSE(); thus returning a zero to the calling

    routine, or by using the WMCLOSE() procedure at any time.

    Either of these two methods will cause the menu to close

    in one of two ways, depending on how the following system

    switch is set:-


       CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface with WMFLOAT();

       and then restoring the objects ID_SC[] background

       screen array, using WMREST_SCR(); to effectively remove

       them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.


       For more information on this system switch refer to

    the WMCLOSE(); procedure and the section on "Winmen

    Declared Types".

       The procedure also checks that no part of the Bar Menu

    will be displayed off the screen, if it would then again

    the programme will abort with an error message. The

    Highlighted menu bar is moved around using the cursor left

    and right keys to move one option at a time or the home

    and end keys to go to the leftmost and rightmost options

    respectively.

.PA

Š        Option Selection can be made with:-

    1) The return key, when the highlighted bar is on the

       required option.

    2) The cursor down key, when the highlighted bar is on the

       required option.

    3) The key that corresponds to the first character of an

       option, regardless of where the highlighted menu bar is

       (Note, this will not move the highlighted bar to that

       option). If there is two or more menu options with the

       same first character, the number of the first one in

       the list is returned.

       For an example of how to set up a Bar Menu with each

    option, when chosen, displaying a drop down type menu, see

    the demonstration programmes source code, Each one of the

    case statements options, for the Bar Menu, could of course

    be replaced with a call to another routine which handled

    another menu of any type, doing it that way as opposed to

    having all the options for all the menus in one routine,

    would keep things much more tidy and manageable.

       When a menu option is highlighted with the menu option

    bar all characters will appear in there original tbc and

    tfc complemented colours, which were calculated from the

    specified tb and tf colours in the call to NEW_MENU(),

    this is true even if they are changed at any time using

    MCHANGE_CHAR(), provided the original tb and tf colours

    were well chosen, this will ensure that the highlighted

    option will always be visible.

       The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR().

.PA

Š      ------------------------------------------------------------------------

      LIST_MENU()                                                  LIST_MENU()

      ------------------------------------------------------------------------


      Function    : Display a menu, previously created using NEW_MENU(), in

      High Level    List Menu format, whose unique identifier is ID, at the

    specified row and column position.

       The area of screen under the menu is saved away in the

    objects ID_SC[] background screen array and the menu is

    linked into the Winmen 3D screen MAP[] system automaticaly

    for full details on this subject refer to the

    WMSAVE_SCR(); procedure and the "maprec" record type,

    which is described in the section "Winmen Declared Types".

       This function will also be called by POP_MENU() if it

    is found that the number of options in the menu exceeds

    23.

       There are also two system switches that affects the way

    in which the LIST_MENU(); function behaves:-


    1) MENU_EXIT_BY_CURSOR := true; Menus will exit using

       cursor or mouse left/right keys/action.

       MENU_EXIT_BY_CURSOR := false; Menus will not exit when

       cursor/mouse Mleft/right keys/action are used.

       MENU_EXIT_BY_CURSOR := true; default.


    2) MENU_ACT_ON_PC := true; Menu functions will return the

       number of the option chosen using the first character

       method.  Don't forget if there is more than one option

       with the same first character, it is the number of the

       first one in the list that will be returned.

       MENU_ACT_ON_PC := false; Menu functions will not return

       the number of the option chosen using the first

       character method.

       MENU_ACT_ON_PC := true; Default.


       The highlighted menu bar will always go to the option

    chosen, when the first character methos of option

    selection is used, regardles of how the switch is set.

       For more detail on these switches refer to the relevant

    sections in the section "Winmen Declared Global

    Variables".

       A menu, when opened for the first time, will have its

    highlighted option bar placed on option 1, for each

    subsequent open, of that particular menu, the highlighted

    menu bar will appear on whatever menu option it was on,

    the last time the menu was closed. This feature applies

    to all menu types and also to the WMSLIDE(); WMMOVE(); and

    WMFLOAT(); procedures.

       The menu record is continually updated to reflect

    changes while the menu is active.


      Syntax      : mc1 := LIST_MENU(ID,l,t,rows_vis);

.PA

Š      Variables   : mc1 : word (W1_400);

    This variable will receive the number of the option

    chosen on the List Menu. One is returned if the topmost

    option is chosen, two for the next option and so on, the

    topmost option is the one at the start of the list, as

    defined for NEW_MENU(), not necassarily the one currently

    at the top of the visable menu on the screen, the topmost

    one may have been scrolled of under the top of the menu.

       A zero is returned if the List Menu is exited from, by

    pressing the escape key, without an option being chosen.

       A particular List Menu has to be the active one, ie.

    open and currently being used, to return an option number.


    ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

       If the ID does not exist or the ID belongs to a window

    the programme will abort with an error message.  (see

    apendix for list).


    l : byte; (B1_78)

    The column in which the leftmost edge of the List Menu is

    to be placed. Must be a value in the range 1-78 or a range

    check error will occure.


    t : byte; (B1_23)

    The row in which the top of the List Menu is to be placed.

    Must be a value in the range 1_23 or a range check error

    will occure.


    rows_vis : byte; (B1_23)

    This is the number of menu options to be displayed on the

    screen when the List Menu is activated. Must be a value in

    the range 1-23 or a range check error will occure.

       The value can be less than the total number of options

    available, if so the other options, not visable can be

    scrolled into and out of the menu as required using the

    cursor keys, as explained in the Tips section below, if

    the number of rows_vis is greater than or equal to the

    number of options available and less than or equal to

    23 (max per screen), then a POP_MENU will automaticaly

    be used, this will be transparent to the user.


      Example     : program LIST_MEN;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1,n : byte;

       m1c : word;

.PA

Š     begin

       getmem(mt,50*81);           {*DYNAMICALY ALLOCATE   *}

       for n := 1 to 50 do         {*MEMORY AND DEFINE MENU*}

       begin                       {*OPTION STRINGS        *}

  str(n,mt^[n]);

  mt^[n] := concat('Menu Option ',mt^[n]);

       end;

       m1 := NEW_MENU(1,1,2,3,4,15,mt,50); {*CREATE MENU*}

       freemem(mt,50*81);          {*RECLAIM MEMORY AND  *}

       m1c := 255;                 {*DELETE POINTER TO IT*}

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := LIST_MENU(m1,5,5,5);

  case m1c of

     1..50 : begin

gotoxy(5,13);

write('Menu Choice ',m1c,' Selected');

     end;

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This function not only positions and displays the List

    Menu on the screen, but also handles all the highlighting

    and selection process and returns the number of the

    option chosen to the user, one being the topmost option

    of the complete list.

       If the menu is already open, only the selection process

    is carried out, ie.  if the List Menu was used previously

    and exited without closing, the next time that particular

    open but non active List Menu is called, the function

    knows not to bother reopening the menu, but to go straight

    into the selection process, this saves a great deal of

    time and looks much nicer.

       The example programme will display a List Menu with 50

    options, but only 5 of them will be visible at any one

    time on screen, the other options being brought into view

    by using the cursor keys as described below.

       A List Menu is closed and exited by pressing either the

    escape key or the cursor left or right keys (See

    MENU_EXIT_BY_CURSOR above), while that menu is the active

    one, this forces a call to WMCLOSE(); thus returning a

    zero to the calling routine, or by using the WMCLOSE()

    procedure at any time.  Either of these three methods will

    cause the menu to close in one of two ways, depending on

    how the following system switch is set:-

.PA

Š        CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface with WMFLOAT();

       and then restoring the objects ID_SC[] background

       screen array, using WMREST_SCR(); to effectively remove

       them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.


       For more information on this system switch refer to

    the WMCLOSE(); procedure and the section on "Winmen

    Declared Types".

       The procedure also checks that no part of the List Menu

    will be displayed off the screen, if it would then again

    the programme will abort with an error message.

       The Highlighted menu bar is moved using the cursor up and

    down keys, to move one option at a time, or the home and

    end keys, to go to the topmost and bottommost visable

    options respectively, when the highlighted menu bar is at

    the top or bottom of the menu, further use of the cursor

    up or down keys will result in list being scrolled, thus

    bringing more options in from the top of the menu while

    those at the bottom are put out of view and vice-versa.

       The list may also be paged while the highlighted menu

    bar is in any position, by using the Pgup and Pgdn keys.

       The absolute top or bottom of the list can be brought

    into view from any position in the menu, by pressing the

    Pgup or Pgdn keys while holding down the Ctrl key

    respectively.

       Option Selection can be made with:-

    1) The return key, when the highlighted bar is on the

       required option.

    2) The key that corresponds to the first character of a

       visable option, regardless of where the highlighted

       menu bar is (Note, this will not move the highlighted

       bar to that option). If there is two or more visable

       menu options with the same first character, the number

       of the first visable one in the list is returned.

       When a menu option is highlighted with the menu option

    bar all characters will appear in there original tbc and

    tfc complemented colours, which were calculated from the

    specified tb and tf colours in the call to NEW_MENU(),

    this is true even if they are changed at any time using

    MCHANGE_CHAR(), provided the original tb and tf colours

    were well chosen, this will ensure that the highlighted

    option will always be visible.

       The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR().

.PA

Š      ------------------------------------------------------------------------

      NEW_MENU()                                                    NEW_MENU()

      ------------------------------------------------------------------------


      Function    : Set up a new menu structure and return the user a unique

      High Level    ID number for future reference to that particular menu.

    The menu structure is independant of the type of menu

    required, so the new menu definition can be used for all

    three menu types, POP_MENU(), LIST_MENU() and BAR_MENU().

    The menu record is created and updated to reflect the

    changes.


      Syntax      : ID := NEW_MENU(btype,bb,bf,tb,tf,pc,mt,rt);


      Variables   : ID : byte;

    Receives the returned unique window identifier.


    btype : byte; (B1_4)

    Type of border required around the menu edge, must be a

    value between 1-4 or a range check error will occure.

    The possible border types are as follows:-

       1 = Double horizontal and double vertical bars.

       2 = Single horizontal and single vertical bars.

       3 = Double horizontal and single vertical bars.

       4 = Single horizontal and double vertical bars.


    bb : byte; (B0_15)

    Border background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    bf : byte; (B0_15)

    Border foregroung colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tb : byte; (B0_15)

    Text background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tf : byte; (B0_15)

    Text foreground colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).

.PA

Š     pc : byte; (B0_15)

    This is the text foreground colour for the first

    character of each menu item, its a good idea to have the

    Pick Character a diferent colour from the rest of the text

    in the menu option so that it stands out, as this

    character can be used to select the menu item if desired.

    Must be a value in the range 0-15 or a range check error

    will occure. (see colour table below).


    mt : pt_mtext; (type

       mtext    = array[1..400] of string[80]

       pt_mtext = ^mtext;)

    This is a pointer variable, which should be used to

    dynamically allocate the above data type, just prior to

    defining the menu option strings, once the menu option

    strings have been defined and the menu created, the

    allocated memory may be reclaimed and the pointer deleted,

    as it will no longer be required by the unit. The example

    shows how it is used to best effect. The maximum number of

    menu options is 400, if this value is exceeded a range

    check error will occure, aborting the programme.


    rt : word (W1_400);

    This is the total number of options in the menu, which must

    be in the range 1..400 or a range check error will occure.


  CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program NEW_MENU;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

.PA

Š     begin

       getmem(mt,3*81);            {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Menu Option 1';  {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';  {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);           {*RECLAIM MEMORY AND  *}

       m1c := 10;                  {*DELETE POINTER TO IT*}

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,5,5);

  case m1c of

     1..3 : begin

       gotoxy(5,8);

       write('Menu Choice ',m1c,' Selected');

    end;

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: A maximum of 255 unique identifiers can be allocated

    the first 20 (0-19) of these are used only for user

    saved screen areas using WMSAVE_SCR(), the rest 236

    (20-255) of these are to be shared between NEW_MENU()

    and NEW_WIN(), if all possible identifiers have been

    allocated or there is insuficient memory left for the

    menu the programme will abort with an error message

    (see apendix for list), although you will most likely

    run out of memory before identifiers, depending upon

    the size of existing menus and windows.

    You can of course free up memory and unique identifiers

    by using WMDELETE() to delete unwanted menus or windows.

    Take care not to overwrite or lose the returned unique

    identifier ID as this is your only link with the

    menu record structure and means of using/deleting the

    menu.

    As stated earlier NEW_MENU() is used to set up the menu

    structure regardless of which type of menu will eventualy

    be used.

    The example shows quite clearly how to define the menu

    options in the most memory efficient way, using the units

    predefined data type "pt_mtext". When a variable of this

    type is declared, as in the example, only enough static

    data space is reserved, at compile time, for the pointer

    variable "mt", no space is allocated for the array of

    strings to which it must eventually point (ie the pointer

    variable "mt" points to nowhere, its null). This space is

    allocated at run time (dynamically) using either the

    new() or getmem() procedures, I have chosen to use the

    later as it enables me to define exactly how much memory

.PA

Š     I need to set asside for the array of strings to which

    "mt" will point, unlike new() which, if used, would have

    set asside enough memory for the complete array of

    strings, or 400*81=32400 bytes, this is because "pt_mtext"

    is actually a pointer to a variable of type array[1..400]

    of string[80] so "mt" would be of the same type, getmem()

    only reserves the number of bytes that you actually tell it

    to, in our case 3*81=243 bytes, the 3 being the number of

    options and the 81 being the number of bytes required by a

    string of string[80], A considerable saving, especialy

    if you were to define several menus of smalish size

    one after the other, without reclaiming any of the

    previous ones, Not forgeting of course that getmem(), like

    new(), still gives you the ability to access your

    dynamically allocated array of strings, in the same way

    as if it were allocated statically ie. mt^[n] := etc....

    The user must exersise caution though when accessing the

    "mt^[n]" strings, if using the example above the user were

    to try and access or fill up the string "mt^[4]" he would

    be in deep trouble, as only enough space was allocated by

    the call to getmem() for 3 strings "mt^[1]", "mt^[2]" and

    "mt^[3]", thus "mt^[4]" would most certainly overwrite

    something else, possibly some other data or even code,

    no run time errors would be generated, strictly speaking

    there is no error, the "mt^[n]" string pointer is well

    within range (array[1..400] of string[80]) and pascal does

    not carry out checks to see if the memory allocated by

    getmem() has been exceeded, this could be a very difficult

    error to spot. if new() had been used instead of getmem()

    this problem would not occure, as all the "array[1.400] of

    string[80]" space would have been allocated, although I

    still think this is a high price to pay for a little extra

    care.

    Once the call to NEW_MENU() has been made, the space

    occupied by the array of strings which "mt" points to

    may be deallocated or reclaimed, by using either the

    freemem() or dispose() procedures, In our case we use

    freemem() as we used getmem() to allocate, it is used in

    the exact same way as getmem(), with exactly the same

    arguements and values, ie. we tell it to free up or                  

    return to the heep 3*81=243 bytes starting at the address 

    pointed to by "mt". WARNING do not use dispose() to

    reclaim memory if you allocated it using getmem(),

    conversly do not use freemem() to reclaim memory if you

    allocated it using new(), as either too much or too little

    memory will be returned to the heep, possibly with

    disasterous concequences.

    Refer to the section in Chapter 1 called "Winmen Declared

    Types" for information on all the record fields plus mtext

    and pt_mtext types. See also the MBAR_COMMENT() procedure 

    for more information on the mtext and pt_mtext types.         

    The example then goes on to use the newly defined menu.

.PA

Š     The function will always allocate a fixed amount of memory

    for the menu record. The amount of memory allocated for

    the option text and border is based upon the number of

    options. The amount of memory allocated for the screen

    under the menu, depends upon the area the menu covers,

    down to a minimum of 324 bytes, this happens to be the

    maximum amount of memory required to save the screen under

    a BAR_MENU, we have to assume the worst case for a BAR_

    MENU (2 lines) as the NEW_MENU() function does not know

    how wide the user wants the BAR_MENU, or weather there is

    to be a BAR_MENU comment line, but this is a very small

    overhead, when compared with savings in code and extra

    comonality afforded.

    When a menu option is highlighted with the menu option bar

    all characters will appear in there original tbc and tfc

    complemented colours, which are calculated from the

    specified tb and tf colours in the call to NEW_MENU(), this

    is true even if they are changed at any time using

    MCHANGE_CHAR(), provided the original tb and tf colours are

    well chosen, this will ensure that the highlighted option

    will always be visible.

    The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR().                       

.PA

Š      ------------------------------------------------------------------------

      POP_MENU()                                                    POP_MENU()

      ------------------------------------------------------------------------


      Function    : Display a menu, previously created using NEW_MENU(), in

      High Level    Pop Menu format, whose unique identifier is ID, at the

    specified row and column position.

       The area of screen under the menu is saved away in the

    objects ID_SC[] background screen array and the menu is

    linked into the Winmen 3D screen MAP[] system automaticaly

    for full details on this subject refer to the

    WMSAVE_SCR(); procedure and the "maprec" record type,

    which is described in the section "Winmen Declared Types".

       This function will also be called from LIST_MENU() if

    it is found that the number of rows_vis is greater than or

    equal to the number of options available and less than or

    equal to 23 (max per screen).

       There are also two system switches that affects the way

    in which the POP_MENU(); function behaves:-


    1) MENU_EXIT_BY_CURSOR := true; Menus will exit using

       cursor or mouse left/right keys/action.

       MENU_EXIT_BY_CURSOR := false; Menus will not exit when

       cursor/mouse Mleft/right keys/action are used.

       MENU_EXIT_BY_CURSOR := true; default.


    2) MENU_ACT_ON_PC := true; Menu functions will return the

       number of the option chosen using the first character

       method.  Don't forget if there is more than one option

       with the same first character, it is the number of the

       first one in the list that will be returned.

       MENU_ACT_ON_PC := false; Menu functions will not return

       the number of the option chosen using the first

       character method.

       MENU_ACT_ON_PC := true; Default.


       The highlighted menu bar will always go to the option

    chosen, when the first character methos of option

    selection is used, regardles of how the switch is set.

    For more detail on these switches refer to the relevant

    sections in the section "Winmen Declared Global

    Variables".

       A menu, when opened for the first time, will have its

    highlighted option bar placed on option 1, for each

    subsequent open, of that particular menu, the highlighted

    menu bar will appear on whatever menu option it was on,

    the last time the menu was closed. This feature applies

    to all menu types and also to the WMSLIDE(); WMMOVE(); and

    WMFLOAT(); procedures.

       The menu record is continually updated to reflect

    changes while the menu is active.


      Syntax      : mc1 := POP_MENU(ID,l,t);

.PA

Š      Variables   : mc1 : word (W1_400);

    This variable will receive the number of the option

    chosen on the Pop Menu. One is returned if the topmost

    option is chosen, two for the next option and so on.

       The topmost option is the one at the start of the list

    as defined for NEW_MENU() and will always be the topmost

    visable option on the screen, as the menu does not scroll.

       A zero is returned if the Pop Menu is exited from, by

    pressing the escape key, without an option being chosen.

    A particular Pop Menu has to be the active one, ie. open

    and currently being used, to return an option number.


    ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

       If the ID does not exist or the ID belongs to a window

    the programme will abort with an error message.  (see

    apendix for list).


    l : byte; (B1_78)

    The column in which the leftmost edge of the List Menu is

    to be placed. Must be a value in the range 1-78 or a range

    check error will occure.


    t : byte; (B1_23)

    The row in which the top of the List Menu is to be placed.

    Must be a value in the range 1_23 or a range check error

    will occure.


      Example     : program POP_MENU;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1,n : byte;

       m1c : word;


    begin

       getmem(mt,20*81);           {*DYNAMICALY ALLOCATE   *}

       for n := 1 to 20 do         {*MEMORY AND DEFINE MENU*}

       begin                       {*OPTION STRINGS        *}

  str(n,mt^[n]);

  mt^[n] := concat('Menu Option ',mt^[n]);

       end;

       m1 := NEW_MENU(1,1,2,3,4,15,mt,20); {*CREATE MENU*}

       freemem(mt,20*81);          {*RECLAIM MEMORY AND  *}

       m1c := 255;                 {*DELETE POINTER TO IT*}

.PA

Š        while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,5,1);

  case m1c of

     1..20 : begin

       gotoxy(5,24);

       write('Menu Choice ',m1c,' Selected');

     end;

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This function not only positions and displays the Pop

    Menu on the screen, but also handles all the highlighting

    and selection process and returns the number of the

    option chosen to the user, one being the topmost option.

       If the menu is already open, only the selection process

    is carried out, ie.  if the Pop Menu was used previously

    and exited without closing, the next time that particular

    open but non active Pop Menu is called, the function knows

    not to bother reopening the menu, but to go straight into

    the selection process, this saves a great deal of time and

    looks much nicer.

       The example programme will display a Pop Menu with 20

    options, all of them being visable.

       If the chosen menu ID has too many options to be

    displayed as a Pop Menu ie.  greater than 23 options, then

    it will automaticaly be displayed as a List Menu, with a

    rows_vis value of 23.

       A Pop Menu is closed and exited by pressing either the

    escape key or the cursor left or right keys (See

    MENU_EXIT_BY_CURSOR above), while that menu is the active

    one, this forces a call to WMCLOSE(); thus returning a

    zero to the calling routine, or by using the WMCLOSE();

    procedure at any time.  Either of these three methods will

    cause the menu to close in one of two ways, depending on

    how the following system switch is set:-


       CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface with WMFLOAT();

       and then restoring the objects ID_SC[] background

       screen array, using WMREST_SCR(); to effectively remove

       them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.

.PA

Š        For more information on this system switch refer to

    the WMCLOSE(); procedure and the section on "Winmen

    Declared Types".

      The procedure also checks that no part of the Pop Menu

    will be displayed off the screen, if it would then again

    the programme will abort with an error message.

       The Highlighted menu bar is moved using the cursor up

    and down keys, to move one option at a time, or the home

    and end keys, to go to the topmost and bottommost options

    respectively, when the highlighted menu bar is at the top

    or bottom of the menu, further use of the cursor up or

    down keys will result in the bar looping to the bottom

    most or topmost options respectively.

       Option Selection can be made with:-

    1) The return key, when the highlighted bar is on the

       required option.

    2) The key that corresponds to the first character of an

       option, regardless of where the highlighted menu bar is

       (Note, this will not move the highlighted bar to that

       option). If there is two or more menu options with the

       same first character, the number of the first one is

       returned.

       When a menu option is highlighted with the menu option

    bar all characters will appear in there original tbc and

    tfc complemented colours, which were calculated from the

    specified tb and tf colours in the call to NEW_MENU(),

    this is true even if they are changed at any time using

    MCHANGE_CHAR(), provided the original tb and tf colours

    were well chosen, this will ensure that the highlighted

    option will always be visible.

       The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR().

.PA

Š












     WINDOWS AND MENUS FOR TURBO PASCAL

     ----------------||----------------

     MENUS PROCEDURES REFERENCE SECTION

.PA

Š      ------------------------------------------------------------------------

      MBAR_COMMENT()                                            MBAR_COMMENT()

      ------------------------------------------------------------------------


      Procedure   : Assign a list of option comments to a particular menu ID,

      High Level    the menu having previously been created using NEW_MENU().

       The comments will only be displayed when that menu ID

    is used as a bar menu, they will become effictive the next

    time the menu is opened as a bar menu, using BAR_MENU();

    or if the menu is already open as a bar menu, but is not

    active, they will be displayed if the menu is moved using

    WMMOVE(); they will not however be displayed if the menu

    is floated with WMFLOAT(); or slid using WMSLIDE(); this

    is because the WMFLOAT(); and WMSLIDE(); procedures do

    not need to call the _MBDISPLAY(); procedure, WMMOVE();

    does, this in turn calls the _MBBAR_ON(); routine which

    actualy displays the comment lines if they exist.

       The comment lines will automaticaly become linked into

    the 3D screen MAP[] system each time a menu that posseses

    them is opened for use as a bar menu, or if already open

    as a bar menu, the next time it is opened as a bar menu,

    or if it is moved with WMMOVE(); as discused above they

    will not be displayed or linked into the 3D screen MAP[]

    if the menu is already open as a bar menu and floated

    with WMFLOAT(); or slid using WMSLIDE();

       Any open and active menu cannot be commented until it

    is closed or becomes non active, as while it is active

    the programme flow in within the menu function its self.

       For more detailed information on the 3D screen MAP[]

    system and its associated data types, records and arrays

    refer to the section on "maprec" in the "Winmen Declared

    Types" section.

       This procedure is not called by any of the functions

    or procedures in the Winmen Unit.

       The menu record is updated to reflect any changes.


      Syntax      : MBAR_COMMENT(ID,mtc);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

       If the ID does not exist or the ID belongs to a window

    the programme will abort with an error message.  (see

    apendix for list).


    mtc: pt_mtext; (type

       mtext    = array[1..400] of string[80]

       pt_mtext = ^mtext;)

    This is a pointer variable, which should be used to

    dynamically allocate the above data type, just prior to

    defining the bar menu comment strings, once the comment 

    strings have been defined and the MBAR_COMMENT() procedure 

    called, the allocated memory may be reclaimed and the 

    pointer deleted, as it will no longer be required by the

.PA

Š     unit. The example shows how it is used to best effect.

       The maximum number of comment strings that can be

    defined is 400, the same as the maximum number of menu

    options. If this number is exceeded, very unlikely, in

    fact impossible the programme will abort with a range

    check error.


      Example     : program COMMENTS;

    uses dos,crt,winmen;

    var

       menu : byte;

       m1c : word;

       mt,mtc : pt_mtext;          {*DEFINE OPTION TEXT &*}

    begin                          {*COMMENT TEXT POINTERS*}

       getmem(mt,3*81);

       mt^[1] := 'Item 1';         {*DEFINE OPTION TEXT*}

       mt^[2] := 'Item 2';

       mt^[3] := 'Item 3';

       menu := NEW_MENU(1,7,9,1,14,15,mt,3);

       freemem(mt,3*81);

       getmem(mtc,3*81);           {*DEFINE COMMENT TEXT*}

       mtc^[1] := 'This Is The Long Comment For Item 1';

       mtc^[2] := 'Shorter Comment For Item 2';

       mtc^[3] := '';              {*MENU ITEM WITH NO*}

       MBAR_COMMENT(menu,mtc);     {*COMMENT TEXT     *}

       freemem(mtc,3*81);


       m1c := 10;

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := BAR_MENU(menu,21,5,38);

  case m1c of

     1..3 : begin

       gotoxy(30,10);

       write('Menu Choice ',m1c,' Selected');

    end;

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure associates a list of bar menu item comments

    with a particular ID.

       There can be one comment for each bar menu option and

    each comment can be up to 80 characters in length.

       Not every bar menu option has to have a comment only

    those required, A bar menu option not requiring a comment

    must have a null comment string assigned to it, as in the

    example above, if this is not done and that particular

    comment text assignment is left out the comment string

    will consist of whatever was in that area of memory at

    that time the length of comment text will also be

    unpredictable, this

.PA

Š     is because Pascal does not automatically clear strings or

    initialise the string length byte to zero.

       The comment will appear on the next line underneath the

    bar menu.

       The colour for the comment textbackground will be taken

    from that IDs record tbc value (Defined in NEW_MENU())

    ie.  the same as the highlighted menu bar background

    colour.

       The colour for the comment text will be taken from that

    IDs record pc value (Defined in NEW_MENU()) i.e the same

    colour as each options first character or pick character.

       The difference between the end of each comment text and

    the end of the menu is filled with the background colour.

       The example shows quite clearly how to define the menu

    options comment text strings in the most memory efficient

    way, using the units predefined data type "pt_mtext", for

    a full discussion of this technique please refer to the

    NEW_MENU() section.

       All the bar menus comments may be changed at any time

    by re-use of the MBAR_COMMENT() procedure.

       You cannot keep some of the old strings by just

    assigning a null string to those particular comments the

    next time you use the MBAR_COMMENT() procedure, as the

    null string effectively overwrites any existing comment

    text, you will need to re-assign the ones you want to keep

    as well.

       Re-use of the MBAR_COMMENT() procedure for particular

    menu ID does not use any extra memory, the existing area

    is used.

       If a particular comment text exceeds the length of the

    menu it will be truncated at the menus edge.

       The programme will abort with an error message, if an

    attempt is made to use MBAR_COMMENT() on a menu ID that

    does not exist, or if the ID refers to a window.

       The comment text strings, for a particular menu record

    once set up, using MBAR_COMMENT(), cannot be erased, only

    overwritten by reuese of the MBAR_COMMENT() procedure, if

    however you do not wish to have the comments displayed

    once thay have been set up, but still want to retain them

    and display them at some other time, then you can do so by

    setting the '.comnt' field of that particular menus record

    to 'false', or back to 'true' when you want them displayed

    again, like this:- ID_WM[ID]^.comnt := false; Where ID is

    the menu identifier (see above), refer to the section in

    Chapter 1 called 'Winmen Declared Types' for further

    information on all the record fields plus mtext and

    pt_mtext types.  See also the NEW_MENU() function for more

    information on the mtext and pt_mtext types.  You may also

    find it usefull to read the description of ID_MC[] in the

    section 'Winmen Declared Variables' as this is the actual

    structure used to hold the bar menu comment strings.

.PA

Š      ------------------------------------------------------------------------

      MCHANGE_CHAR()                                            MCHANGE_CHAR()

      ------------------------------------------------------------------------


      Procedure   : Change a character in menu "ID", option "row", position

      High Level    "col" to the character in "new_char", also assigning the

    new textbackground and foreground colours "tb" and "tf"

    respectively. The ID can only refer to a list or pop menu

    when open or closed or a bar menu when closed. The nemu

    must have previously been created using NEW_MENU().

    The menu record is not affected by this command.


      Syntax      : MCHANGE_CHAR(ID,row,col,new_char,tb,tf);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window the

    programme will abort with an error message. (see apendix

    for list). 


    row : byte;

    The "row" number corresponds to the menu option as defined

    in the option text list passed to NEW_MENU(), "row" 1 will

    be the first option in that list, "row" 2 the second etc..


    col : byte; (B1_79)

    The "col" number corresponds to the menu options column

    as defined in the option text list passed to NEW_MENU(),

    "col" 1 will be the first character of the option, from

    the left hand side. Col must be in the range 1-79 or a 

    range check error will occure


    new_char : char;

    This is the ascii character/value with which to replace

    the existing ascii character/value at position "row",

    "col". The character/value can be any valid ascii value

    in the range 0-255.


    tb : byte; (B0_15)

    Text background colour, for the "new_char" must be a value

    in the range 0-15 or a range check error will occure. (see

    colour table below).


    tf : byte; (B0_15)

    Text foreground colour, for the "new_char" must be a value

    in the range 0-15 or a range check error will occure. (see

    colour table below).

.PA

Š   CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program CHANGE_CHAR;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);            {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Change a Char';  {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Open & Close';   {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);           {*RECLAIM MEMORY AND  *}

       m1c := 10;                  {*DELETE POINTER TO IT*}

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,31,8);

  case m1c of

     1 : MCHANGE_CHAR(m1,2,1,chr(random(255)),8,15);

end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will change any character and its text-

    background and foreground colours in a menu option array

    permenantly, or untill changed again using this procedure.

    The corresponding screen word/character is also updated

    provided the menu is currently open and in the case of a

    list menu, the character at "row","col" is visible on the

    screen.

.PA

Š     As mentioned above list and pop menus can be open or closed

    when this procedure is used, however a bar menu must be

    closed for this procedure to operate correctly, the change

    will be effective the next time the bar menu is opened. If

    this procedure is used on an open bar menu the new char

    with its textforeground and background colours will most

    probably appear somewhere else on the screen, not in its

    correct position, the change will be correct after the bar

    menu has been closed and re-opened, as the mmenu screen

    format arrays are in a common format for all menus

    regardless of there type, its only there respective display

    procedures that differ.

    This procedure may be updated at a future date, so that bar

    menus can updated correctly while still open.

    The new textbackground and foreground colours specified

    only have effect on the new character, and will stay in

    effect untill changed again, even if the menu is closed and

    re-opened, this is because the mmenu word array, which is

    in screen format, is never rebuilt again as it was in the

    call to NEW_MENU(), so the originally defined tb and tf

    values have no effect on the changed character(s).

    If it is found that the character to be changed is on the

    same row as the highlighted menu bar, then the screen is

    updated using the original tbc and tfc complemented colours

    otherwise a changed character with poorly chosen colours

    may become invisable when highlighted.

    When a menu option containing changed characters is high-

    lighted with the menu option bar, all characters will still

    appear in there original tbc and tfc complemented colours,

    which were calculated from the specified tb and tf colours

    in the call to NEW_MENU(), provided the original tb and tf

    colours were well chosen, this will ensure that the high-

    lighted option will always be visible, regardles of how

    individual characters are changed.

    The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR().

    The example above changes the second character of menu

    option 2 each time option 1 is chosen. The character value

    will be random, the colours will always be tb=8 & tf=15.

.PA

Š      ------------------------------------------------------------------------

      MPIC_COL()                                                    MPIC_COL()

      ------------------------------------------------------------------------


      Procedure   : Change the pick (first) characters foreground colour to

      High Level    that of "pc" for each menu option in the menu "ID", which

    was previously created using NEW_MENU().

    The menu record is updated to reflect any changes. 


      Syntax      : MPIC_COL(ID,pc);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window the

    programme will abort with an error message. (see apendix

    for list). 


    pc : byte; (B0_15)

    This is the text foreground colour for the first

    character of each menu item, its a good idea to have the

    Pick Character a diferent colour from the rest of the text

    in the menu option so that it stands out, as this

    character can be used to select the menu item if desired.

    Must be a value in the range 0-15 or a range check error

    will occure. (see colour table below).


  CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program PIC_COL;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                  {*DEF OPTION TXT PTR*}

       m1 : byte;

       m1c : word;

.PA

Š     begin

       getmem(mt,3*81);                {*DYNAMICALY ALLOCATE*}

       mt^[1] := 'Change Pick Colour'; {*MEM AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';      {*OPTION STRINGS     *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3);{*CREATE MENU*}

       freemem(mt,3*81);               {*RECLAIM MEMORY AND  *}

       m1c := 10;                      {*DELETE POINTER TO IT*}

       while (m1c <> 0) do             {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,31,8);

  case m1c of

     1 : begin           {*RANDOMLY CHANGE PIC COLOUR*}

    MPIC_COL(m1,random(15));

    WMCLOSE(m1);

end;

  end;

       end;

       normvideo;

    end.


      Notes Rules

      Tips & Traps: This procedure changes all the menu options first char-

    acters colour to the value sent in "pc".

    This procedure can be used regardless of the state of a

    particular menu.

    The change will be permenant or untill changed again

    using MPIC_COL() or MCHANGE_CHAR() and will only become

    effective when the menu is next opened for use.

    Can be used on all menu types.

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_END()                                                _MBBAR_END()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure which is called by BAR_MENU() to move

      Low Level     the selection bar of bar menu ID to the rightmost option,

    regardless of where it is.

    if the highlighted menu bar is already at the rightmost 

    position, no action is taken. 

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MBBAR_END(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_END;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Bar To End Option';{*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';    {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     1 : _MBBAR_END(m1);     {*MOVE OPTION BAR TO END*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure moves a bar menu, option bar, to the 

    rightmost option in the menu, regardless of where it is,

    or if the highlighted bar is already at the rightmost 

    position, no action is taken. 

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                           

    The example will move the highlighted menu option bar to

    the rightmost option each time option 1 is chosen.          

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_HOME()                                              _MBBAR_HOME()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure which is called by BAR_MENU() to move

      Low Level     the selection bar of bar menu ID to the leftmost option in 

    menu, regardless of where it is.

    if the highlighted menu bar is already at the leftmost 

    position, no action is taken. 

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MBBAR_HOME(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_HOME;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Menu Option 1';    {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Go To Home Option';{*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     2 : _MBBAR_HOME(m1);    {*MOVE OPTION BAR LEFT*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure moves a bar menu option bar to the leftmost

    position, regardless of where it is, or if the highlighted

    bar is already at the leftmost position, no action is 

    taken. 

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                           

    The example will move the highlighted menu option bar to

    the leftmost option each time option 2 is chosen.          

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_LEFT()                                              _MBBAR_LEFT()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure which is called by BAR_MENU() to move

      Low Level     the selection bar of bar menu ID one option to the left,

    looping to the last option if the highlighted menu bar is

    already at the leftmost position.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MBBAR_LEFT(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_LEFT;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Bar Left 1 Option';{*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';    {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     1 : _MBBAR_LEFT(m1);    {*MOVE OPTION BAR LEFT*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure moves a bar menu option bar one option to

    the left, or if the highlighted bar is already at the

    leftmost position it is looped to the rightmost option.

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

.PA

Š     The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                           

    The example will move the highlighted menu option bar one

    option to the left each time option 1 is chosen.                          

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_OFF()                                                _MBBAR_OFF()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by _MBBAR_LEFT(), _MBBAR_RIGHT()

      Low Level     _MBBAR_HOME() and _MBBAR_END() to turn off the highlighted

    menu bar in a bar menu.

    The menu ID must have been previously created by using

    NEW_MENU().                                               

    The menus record is not affected by this command.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MBBAR_OFF(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().                                          

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_OFF;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                 {*DEF OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);               {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Turn Bar Off';      {*MEM AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';     {*OPTION STRINGS     *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);              {*RECLAIM MEMORY AND  *}

       m1c := 10;                     {*DELETE POINTER TO IT*}

       while (m1c <> 0) do            {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     1 : _MBBAR_OFF(m1);      {*TURN OPTION BAR OFF*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure turns off a highlighted menu bar on a bar

    menu, by redrawing it in its normal attributes, using the

    originally defined "tb" and "tf" colour values sent to 

    NEW_MENU().

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                           

    The example will turn off the highlighted menu option bar

    each time option 1 is chosen.                             

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_ON()                                                  _MBBAR_ON()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by _MBBAR_LEFT(), _MBBAR_RIGHT()

      Low Level     _MBBAR_HOME(), _MBBAR_END() and _MBDISPLAY() to turn on the 

    highlighted menu bar in a bar menu, plus any associated 

    comment text for this menu ID, which was created using 

    MBAR_COMMENT().  

    The menu ID must have been previously created by using

    NEW_MENU().                                               

    The menus record is not affected by this command.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MBBAR_ON(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().                                          

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_ON;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                 {*DEF OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);               {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Turn Bar On';       {*MEM AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';     {*OPTION STRINGS     *}

       mt^[3] := 'Bar Off';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);              {*RECLAIM MEMORY AND  *}

       m1c := 10;                     {*DELETE POINTER TO IT*}

       while (m1c <> 0) do            {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     1 : _MBBAR_ON(m1);       {*TURN OPTION BAR ON*}

     3 : _MBBAR_OFF(m1);      {*TURN OPTION BAR OFF*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure turns on a highlighted menu bar on a bar

    menu, this is achieved by changing the screen ram character 

    word's colour byte, using this ID's original "tbc" and 

.PA

Š     "tfc" complemented colours, which were calculated from the 

    specified "tb" and "tf" colours in the call to NEW_MENU(), 

    rather than using the colour values already in the mmenu 

    character word array and complementing them,as they may be

    poor colours for complementing, provided the original "tb" 

    and "tf" colours were well chosen, this will ensure that 

    the highlighted option will always be visible,regardles of

    how individual characters may have been changed using the 

    MCHANGE_CHAR() procedure. 

    The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR(). 

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    Any comment text associated with the menu is also drawn

    on, on the line under the actual bar menu. The comment

    text, if too long for the menu, will be truncated at the

    end of the menu, or if too short, the remainder, between 

    the end of the comment text and the end of the menu will 

    be filled with complemented textbackground colour only.

    The colour for the comment textbackground will be taken

    from that IDs record "tbc" value (Defined in NEW_MENU())

    ie. the same as the highlighted menu bar background colour.

    The colour for the comment text will be taken from that

    IDs record "pc" value (Defined in NEW_MENU()) i.e the same

    colour as each options first character or pick character. 

    The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                           

    The example will turn on the highlighted menu option bar

    each time option 1 is chosen, and off when option 2 is

    chosen.

.PA

Š      ------------------------------------------------------------------------

      _MBBAR_RIGHT()                                            _MBBAR_RIGHT()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure which is called by BAR_MENU() to move

      Low Level     the selection bar of bar menu ID one option to the right,

    looping to the first option if the highlighted menu bar is

    already at the rightmost position.

    The menu ID must have been previously created by using

    NEW_MENU().                                               

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MBBAR_RIGHT(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.


      Example     : program MBBAR_RIGHT;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                 {*DEF OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);               {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Bar Right 1 Option';{*MEM AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';     {*OPTION STRINGS     *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);              {*RECLAIM MEMORY AND  *}

       m1c := 10;                     {*DELETE POINTER TO IT*}

       while (m1c <> 0) do            {*USE THE MENU*}

       begin

  m1c := BAR_MENU(m1,5,5,60);

  case m1c of

     1 : _MBBAR_RIGHT(m1);    {*MOVE OPTION BAR RIGHT*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure moves a bar menu option bar one option to

    the right, or if the highlighted bar is already at the

    rightmost position it is looped to the leftmost option.

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on bar

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open bar menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                    

    The example will move the highlighted menu option bar one

    option to the right each time option 1 is chosen.          

.PA

Š      ------------------------------------------------------------------------

      _MBDISPLAY()                                                _MBDISPLAY()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by BAR_MENU() to actually display

      Low Level     the bar menu on the screen at the position requested in the

    call to BAR_MENU().

       This procedure does not save away the screen under the

    bar menu being displayed, niether does it link the bar

    menu into the 3D screen MAP[] system, for details on both

    of these subjects refer to the WMSAVE_SCR(); procedure and

    the sub-section on "maprecs" in the "Winmen Declared

    Types" section.

       The menu ID must have been previously created by using

    NEW_MENU().

       The menus record is updated to reflect the changes.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.


      Syntax      : _MBDISPLAY(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than bar menu the results could be

    unpredictable.                                            


      Example     : program MBDISPLAY;


    uses dos,crt,winmen;


    var

       ID : pt_wmrec;                  {*DEF POINTER TO WMREC*}

       mt : pt_mtext;                  {*DEF OPTION TEXT PTR*}

       blen,nrow,m1,key,l,t,ncol_old : byte;{*DEF OTHER VARBS*}


    begin

       getmem(mt,3*81);             {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Key Pad 6';       {*MEM AND DEFINE MENU*}

       mt^[2] := 'Will Move Bar';   {*OPTION STRINGS     *}

       mt^[3] := '1 Option Right';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);            {*RECLAIM TXT STRINGS MEM*}

       {**************************} {*AND DELETE POINTER*}

       ID := ID_WM[m1];             {*POINT ID TO m1 MENU REC*}

       blen := 60; l := 7; t := 7;  {*INT BAR LEN & TR OF MEN*}

       ID^.gap := (blen-ID^.sumopt) div (ID^.nrow-1); {*GAP*}

       ID^.cols_vis := blen;        {*BAR COLUMNS VISABLE*}

       ncol_old := ID^.ncol;        {*SAVE POP/LIST COLS*}

       ID^.ncol := blen;            {*USE BAR COLS VALUE*}

.PA

Š        if(ID^.comnt = true) then    {*CHECK FOR COMMENT TEXT*}

  nrow := 2                 {*SET NROW=2 IF CMT TXT=Y*}

       else

  nrow := 1;                {*SET NROW=1 IF CMT TXT=N*}

       _MCHK_ON_SCREEN(m1,'MY_MENU',l,t,nrow); {*CHECK VALID*}

       WMSAVE_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*SAVE SCREEN*}

       _MBDISPLAY(m1);              {*DISPLAY THE BAR MENU*}

       ID^.ncol := ncol_old;        {*REPLACE POP/LIST COLS*}

       {**************************}

       key := 0;                    {*INITIALISE KEY*}

       while (key <> 27) do         {*USE THE MENU*}

       begin                        {*WHILE ESC NOT PRESSED*}

  key := ord(readkey);      {*WAIT FOR A KEYPRESS*}

  case key of               {*CHECK SCAN CODE*}

     77 : _MBBAR_RIGHT(m1); {*MOVE OPTION BAR RIGHT*}

  end;

       end;

       WMREST_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*RESTO SCREEN*}

       normvideo;

    end.               


      Rules Notes

      Tips & Traps: This procedure will actually display the bar menu on the

    screen, in the position requested in the call to BAR_MENU()

    and turn on the highlighted menu bar over option one, the

    leftmost option, it will do this each time it is called.

    But as can be seen from the above example a fair amount of

    work has to be done in firstly setting up that particular

    menus record variables, the area of code in the example 

    between the {*********} markings shows the minimum amount 

    of setting up required if the call to _MBDISPLAY() is to

    be sucessful, this includes the calls to _MCHK_ON_SCREEN()

    and WMSAVE_SCR(), as these procedures also contribute

    towards setting record variables for the menu in question.

    All the record variables in the above example begin with

    the identifier "ID^." and are appended with the appropriate

    record variable identifier.

       A full list of all the global wmrec record variables,

    all other global variables and constants, along with all

    the units declared types, can be found, with an

    explanation of each elsewhere in this reference guide.

       The example will actually put up a three option bar

    menu and allow you to move the highlighted option bar one

    option to the right each time the nemeric pad "6" key is

    pressed, the "esc" key will exit the menu.  The procedure

    achieves its speed by using direct screen ram access

    techniques, to place characters directly into screen ram.

       The procedure will only work correctly when used on bar

    menus.  Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

.PA

Š        Being a low level procedure no checks are carried out

    on any data passed to it by the user, so make sure the ID

    is for a valid open or closed bar menu only, not any other

    menu type or a window, the result of doing this will

    possibly corrupt the record or be unpredictable.

.PA

Š      ------------------------------------------------------------------------

      _MCHK_ON_SCREEN()                                      _MCHK_ON_SCREEN()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the following functions:-

      Low Level     BAR_MENU(), LIST_MENU() and POP_MENU().

    This procedure checks to make sure that no part of the 

    menu will go off the screen when it is displayed, it is

    an error to do so and the procedure will halt the current

    programme with an error message if it is found it will,

    (see appendix for list).

    If the check is sucessfull the procedure goes on to update

    the menus record with the supplied "ID^.l" and "ID^.t" 

    values and also calculated values for "ID^.r" and "ID^.b"

    as these values are needed by all the calling functions

    in order to actually display the menu.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MCHK_ON_SCREEN(ID,proc,l,t,nrow);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window the

    results could be unpredictable.


    proc : string;

    This string should be the name of the function or procedure

    that is calling the _MCHK_ON_SCREEN() procedure, if say a 

    procedure called MYPROC() were to call _MCHK_ON_SCREEN()

    it would look like this _MCHK_ON_SCREEN(IDB,'MYPROC');

    Although of course in reality you could use any string you

    want up to a maximum of 255 characters.

    If the string is longer than 255 characters a range check

    error will occure.                                        


    l : byte; (B1_78)

    Leftmost edge of the menu including border, must be a

    value between 1-78, to be consistant with the way the unit

    works, if not then the results may be unpredictable. 


    t : byte; (B1_23)

    Topmost edge of the menu including border, must be a value

    between 1-23, to be consistant with the way the unit works

    if not then the results may be unpredictable.


    nrow : byte;

    This value is the absolute number of rows that the

    menu area covers or its depth (b-t+1). Must be a value in 

    the range 3-25 to be consistant with the way the unit works 

    if not then the results may be unpredictable.                             

.PA

Š      Example     : procedure MENU_PROC(ID : byte; a,b,c : sometype);

    var

       variables.....

    begin

       _MCHK_ON_SCREEN(ID,'MENU_PROC',10,5,8);

       remainder

  of

    procedure

statements

    end;                                                      


      Rules Notes

      Tips & Traps: No special instructions to be observed.                   

.PA

Š      ------------------------------------------------------------------------

      _MDISPLAY()                                                  _MDISPLAY()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by POP_MENU() and LIST_MENU() to 

      Low Level     actually display the pop/list menu on the screen at the 

    position requested in the call to POP_MENU() or LIST_MENU()  

    The menu ID must have been previously created by using 

    NEW_MENU().

       This procedure does not save away the screen under the

    bar menu being displayed, niether does it link the bar

    menu into the 3D screen MAP[] system, for details on both

    of these subjects refer to the WMSAVE_SCR(); procedure and

    the sub-section on "maprecs" in the "Winmen Declared

    Types" section.

       The menus record is updated to reflect the changes.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.


      Syntax :      _MDISPLAY(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop or list the results could be

    unpredictable.                                            


      Example     : program MDISPLAY;


    uses dos,crt,winmen;


    var

       ID : pt_wmrec;               {*DEF POINTER TO WMREC*}

       mt : pt_mtext;               {*DEF OPTION TEXT PTR*}

       m1,key : byte;               {*DEF SUNDRY VARBS*}


    begin

       getmem(mt,3*81);             {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Key Pad 2';       {*MEM AND DEFINE MENU*}

       mt^[2] := 'Will Move Bar';   {*OPTION STRINGS     *}

       mt^[3] := '1 Option Down';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);            {*RECLAIM TXT STRINGS MEM*}

       {**************************} {*AND DELETE POINTER*}

       ID := ID_WM[m1];             {*POINT ID TO m1 MENU REC*}

       ID^.rows_vis := ID^.nrow-2   {*VISIBLE=TOTAL-BORDER*}

       _MCHK_ON_SCREEN(m1,'MY_MENU',20,10,ID^.nrow);{*CHK POS*}

       WMSAVE_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*SAVE SCREEN*}

       _MDISPLAY(m1);               {*DISPLAY THE POP MENU*}

       {**************************}

.PA

Š        key := 0;                    {*INITIALISE KEY*}

       while (key <> 27) do         {*USE THE MENU*}

       begin                        {*WHILE ESC NOT PRESSED*}

  key := ord(readkey);      {*WAIT FOR A KEYPRESS*}

  case key of               {*CHECK SCAN CODE*}

     80 : _MPLBAR_DO(m1);   {*MOVE OPTION BAR DOWN*}

  end;

       end;

       WMREST_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*RESTO SCREEN*}

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will actually display the pop or list menu

    on the screen, in the position requested in the call to 

    BAR_MENU() and turn on the highlighted menu bar over option 

    one, the topmost option, it will do this each time it is 

    called. The ID^.rows_vis value must be set to the number 

    of option rows you actually want displayed on the screen,

    for a pop menu this will be ID^.nrow-2 (all rows less the

    border), but for a list menu of course this value can be

    anything between 1..23 as long as the value is less than

    the total number of opion rows in the menu.

       As can be seen from the above example a fair amount of

    work has to be done in firstly setting up that particular

    menus record variables, the area of code in the example

    between the {*********} markings shows the minimum amount

    of setting up required if the call to _MDISPLAY() is to be

    sucessful, this includes the calls to _MCHK_ON_SCREEN()

    and WMSAVE_SCR(), as these procedures also contribute

    towards setting record variables for the menu in question.

       All the record variables in the above example begin

    with the identifier "ID^." and are appended with the

    appropriate record variable identifier.

       A full list of all the global wmrec record variables,

    all other global variables and constants, along with all

    the units declared types, can be found, with an

    explanation of each elsewhere in this reference guide.

       The example will actually put up a three option pop

    menu and allow you to move the highlighted option bar one

    option downwards each time the nemeric pad "2" key is

    pressed, the "esc" key will exit the menu.  The procedure

    achieves its speed by using direct screen ram access

    techniques, to place characters directly into screen ram.

       The procedure will only work correctly when used on pop

    and list menus.  Using it on other menu types will trash

    the screen and put incorrect values into that menus record

    possibly rendering it useless.

       Being a low level procedure no checks are carried out

    on any data passed to it by the user, so make sure the ID

    is for a valid open or closed pop or list menu only, not

    any other menu type or a window, the result of doing this

    will possibly corrupt the record or be unpredictable.

.PA

Š      ------------------------------------------------------------------------

      _MLBAR_BLST()                                              _MLBAR_BLST()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to move the high-

      Low Level     lighted menu bar to the very last phisical option in the 

    list, in a list menu only. This last phisical option may or 

    may not be one of the visible options currently on the 

    screen, it will be the last visible option in the list menu

    after execution has completed.

    No action is taken if the highlighted menu bar is already

    at the last phisical option in the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MLBAR_BLST(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


      Example     : program MLBAR_BLST;


    uses dos,crt,winmen;


    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

       cs : string[5];


    begin

       getmem(mt,15*81);             {*DYNAMICALY ALLOCATE   *}

       for c := 1 to 15 do           {*MEMORY AND DEFINE MENU*}

       begin                         {*OPTION STRINGS*}

  str(c,cs);

  mt^[c] := 'Menu Option '+cs;

       end;

       mt^[1] := 'Move Bar To End Of List';

       mt^[3] := 'Move Bar To End Of List';

       mt^[5] := 'Move Bar To End Of List';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,15);    {*CREATE MENU*}

       freemem(mt,15*81);            {*RECLAIM MEMORY AND  *}

     {*DELETE POINTER TO IT*}

.PA

Š        m1c := 20;

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := LIST_MENU(m1,15,10,5);

  case m1c of

     1,3,5 : _MLBAR_BLST(m1);{*MOVE OPT BAR TO LAST*}

  end;                       {*PHISICAL OPT IN LIST*}

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: Internal procedure called by LIST_MENU() to move the high

    lighted menu bar to the very last phisical option in the 

    list, in a list menu only.This last phisical option may or 

    may not be one of the visible options currently on the 

    screen it will be the last visible option in the list menu

    after execution has completed,with as many previous

    options above it as was specified by rows_vis in the call

                    to LIST_MENU().

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on list

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    foò á valiä opeî lisô menõ only¬noô anù otheò menõ typå or

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                    

    The example will move the highlighted menu option bar to

    the very last phisical option in the list each time

    options 1, 3 or 5 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MLBAR_END()                                                _MLBAR_END()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to move the high-

      Low Level     lighted menu bar to the last/bottommost visible option in a

    list menu only.

    No action is taken if the highlighted menu bar is already

    at the last/bottommost visible option of the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MLBAR_END(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


      Example     : program MLBAR_END;


    uses dos,crt,winmen;


    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1,c : byte;

       m1c : word;

       cs : string[5];


    begin

       getmem(mt,15*81);             {*DYNAMICALY ALLOCATE   *}

       for c := 1 to 15 do           {*MEMORY AND DEFINE MENU*}

       begin                         {*OPTION STRINGS        *}

  str(c,cs);

  mt^[c] :='Menu Option '+cs;

       end;

       mt^[1] := 'Move Bar To Last Visible Option';

       mt^[7] := 'Move Bar To Last Visible Option';

       mt^[12] := 'Move Bar To Last Visible Option';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,15);    {*CREATE MENU*}

       freemem(mt,15*81);            {*RECLAIM MEMORY AND  *}

.PA

Š        m1c := 20;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := LIST_MENU(m1,15,10,5);

  case m1c of

     1,7,12 : _MLBAR_END(m1);{*MOVE OPTION BAR TO END*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a list menu only, to the last/bottommost visible option.

    If the bar is found to be at the bottommost visible option

    already, no action is taken.

    The last or bottommost visible option may not of course be

    the last phisical option in the list.

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on list

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open list menu only, not any other menu type or

    a window, the result of doing this will possibly corrupt

    the record or be unpredictable.

    The example will move the highlighted menu option bar to

    the last/bottommost visible option each time options 1, 7

    or 12 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MLBAR_HOME()                                              _MLBAR_HOME()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to move the high-

      Low Level     lighted menu bar to the first/topmost visible option in a

    list menu only.

    No action is taken if the highlighted menu bar is already

    at the first/topmost visible option of the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MLBAR_HOME(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


      Example     : program MLBAR_HOME;


    uses dos,crt,winmen;


    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1,c : byte;

       m1c : word;

       cs : string[5];


    begin

       getmem(mt,15*81);             {*DYNAMICALY ALLOCATE   *}

       for c := 1 to 15 do           {*MEMORY AND DEFINE MENU*}

       begin                         {*OPTION STRINGS        *}

  str(c,cs);

   mt^[c] :='Menu Option '+cs;

       end;

       mt^[4] := 'Move Bar To First Visible Option';

       mt^[8] := 'Move Bar To First Visible Option';

       mt^[15] := 'Move Bar To First Visible Option';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,15);    {*CREATE MENU*}

       freemem(mt,15*81);            {*RECLAIM MEMORY AND  *}

     {*DELETE POINTER TO IT*}

.PA

Š        m1c := 20;                    {*USE THE MENU*}

       while (m1c <> 0) do

       begin

  m1c := LIST_MENU(m1,15,10,5);

  case m1c of

     4,8,15 : _MLBAR_HOME(m1);{*MOVE OPT BAR TO TOP*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a list menu only, to the first/topmost visible option.

    If the bar is found to be at the topmost visible option

    already, no action is taken.

    The first or topmost visible option may not of course be

    the first phisical option in the list.

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on list

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open list menu only, not any other menu type or

    a window, the result of doing this will possibly corrupt

    the record or be unpredictable.

    The example will move the highlighted menu option bar to

    the first/topmost visible option each time options 4, 8

    or 15 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MLBAR_TLST()                                              _MLBAR_TLST()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to move the high-

      Low Level     lighted menu bar to the very first phisical option in the

    list, in a list menu only. This first phisical option may

    or may not be one of the visible options currently on the

    screen, it will be the first visible option in the list

    menu after execution has completed.

    No action is taken if the highlighted menu bar is already

    at the first phisical option in the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MLBAR_TLST(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


Example   : program MLBAR_TLST;


    uses dos,crt,winmen;


    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

       cs : string[5];


    begin

       getmem(mt,15*81);             {*DYNAMICALY ALLOCATE   *}

       for c := 1 to 15 do           {*MEMORY AND DEFINE MENU*}

       begin                         {*OPTION STRINGS*}

  str(c,cs);

  mt^[c] := 'Menu Option '+cs;

       end;

       mt^[5] := 'Move Bar To Top Of List';

       mt^[8] := 'Move Bar To Top Of List';

       mt^[15] := 'Move Bar To Top Of List';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,15);    {*CREATE MENU*}

       freemem(mt,15*81);            {*RECLAIM MEMORY AND  *}

     {*DELETE POINTER TO IT*}

.PA

Š        m1c := 20;

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := LIST_MENU(m1,15,10,5);

  case m1c of

     5,8,15  : _MLBAR_TLST(m1);

  end;                       {*MOVE OPT BAR TO FIRST*}

       end;                          {*PHISICAL OPT IN LIST*}

       normvideo;

    end.


      Rules Notes

      Tips & Traps: Internal procedure called by LIST_MENU() to move the high-

    lighted menu bar to the very first phisical option in the

    list, in a list menu only. This first phisical option may

    or may not be one of the visible options currently on the

    screen, it will be the first visible option in the list

    menu after execution has completed, with as many subsequent

    options below it as was specified by rows_vis in the call

    to LIST_MENU().

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on list

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open list menu only, not any other menu type or

    a window, the result of doing this will possibly corrupt

    the record or be unpredictable.

    The example will move the highlighted menu option bar to

    the very first phisical option in the list each time 

    options 5, 8 or 15 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MLMOV_DO()                                                  _MLMOV_DO()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to scroll or page

      Low Level     down through the options in a list menu, towards the bottom

    of the list, this procedure does not move the highlighted

    menu bar, it will remain in the same position.

    The scrolling can be either by a single menu option at a

    time or by a page at a time.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect any changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MLMOV_DO(ID,move);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


    move : char;

    This move character must be one of the four following

    characters 'S','s' or 'P','p' or its ascii value equivalent

    If 'S' is sent then the list will be scrolled upwards by

    one option only, moving us towards the end of the list,

    if the bottommost visible option is already the bottommost

    phisical option (end of list) then no action is taken.

    If 'P' is sent then the list will be paged upwards by the

    number of options visible on the screen, or the rows_vis

    value used in the call to LIST_MENU(), moving us towards

    the end of the list, if there is insufficient options left

    for a full page (rows left < rows_vis) then the remainder

    will be paged into view with the bottommost phisical option

    in the list becoming the bottommost visible option on the

    screen. if the bottommost visible option is already the

    bottommost phisical option (end of list) then no action is

    taken.

    If any character other than 'S' or 's' is recieved then it

    is assumed to be a 'P' or 'p', no checks are actually

    carried out to see if it is a 'P' or a 'p' so take care.


      Example     : program MLMOV_DU;


    uses dos,crt,winmen;

.PA

Š     var

       ID : pt_wmrec;               {*DEF POINTER TO WMREC*}

       mt : pt_mtext;               {*DEF OPTION TEXT PTR*}

       m1,key,c : byte;             {*DEF SUNDRY VARBS*}

       mid_row : word;

       cs : string[5];


    begin

       getmem(mt,25*81);            {*DYNAMICALY ALLOC   *}

       for c := 1 to 15 do          {*MEMORY AND DEFINE MENU*}

       begin                        {*OPTION STRINGS*}

  str(c,cs);

  mt^[c] := 'Menu Option '+cs;

       end;

       mt^[1] :=  'Key Pad 2 = Down';{*MEM AND DEFINE MENU*}

       mt^[25] := 'Key Pad 8 = Up'; {*OPTION STRINGS     *}

       m1 := NEW_MENU(1,1,2,3,4,15,mt,25); {*CREATE MENU*}

       freemem(mt,25*81);           {*RECLAIM TXT STRINGS MEM*}

       {**************************} {*AND DELETE POINTER*}

       ID := ID_WM[m1];             {*POINT ID TO m1 MENU REC*}

       ID^.rows_vis := 9            {*VISIBLE ROWS=9*}

       _MCHK_ON_SCREEN(m1,'MY_MENU',20,8,ID^.rows_vis-2);

       WMSAVE_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*SAVE SCREEN*}

       _MDISPLAY(m1);               {*DISPLAY THE LIST MENU*}


       key := 0;                    {*INITIALISE KEY*}

       while (key <> 27) do         {*USE THE MENU*}

       begin                        {*WHILE ESC NOT PRESSED*}

  key := ord(readkey);      {*WAIT FOR A KEYPRESS*}

  mid_row := ID^.trow+ID^.rows_vis-1;

  mid_row := mid_row - (ID^.rows_vis div 2);

  case key of               {*CHECK SCAN CODE*}

     80 : begin

     if(ID^.row < mid_row) then

_MPLBAR_DO(m1);       {*MOVE BAR DOWN*}

     else

if(ID^.trow+ID^.rows_vis-1; <

       ID^.nrow-2) then

   _MLMOV_DO(m1,'S'); {*SCROLL LIST*}

else

   if(ID^.row < ID^.nrow-2) then

      _MPLBAR_DO(m1); {*MOVE BAR DOWN*}

  end;

.PA

Š      72 : begin

     if(ID^.row > mid_row) then

_MPLBAR_UP(m1);       {*MOVE BAR UP*}

     else

if(ID^.trow > 1) then

   _MLMOV_UP(m1,'S'); {*SCROLL LIST*}

else

   if(ID^.row > 1) then

      _MPLBAR_UP(m1); {*MOVE BAR UP*}

  end;

  end;

       end;

       WMREST_SCR(m1,ID^.l,ID^.t,ID^.r,ID^.b); {*RESTO SCREEN*}

       normvideo;

    end.

    {**************************}


      Rules Notes

      Tips & Traps: This procedure scrolls the options of a list menu up under

    the menu border, so that we are moving down towards the end

    of the phisical list.

    Move can be 'S' or 's' for scroll up one option, this does

    not preassume that the current row, ID^.row, is the bottom

    most option, thus allowing the options to scroll up with

    the highlighted bar anywhere on the menu, the menu bar is

    left in its original position.

    Move can be 'P' or 'p' for page up, ID^.rows_vis, scrolls

    up a page at a time, again no assumptions are made, thus

    allowing the options to scroll up with the highlighted bar

    anywhere on the menu, the menu bar is left in its original

    position.

    The above example code between the areas marked with {****}

    represents what would be the core of a new menu function

    possibly called LIST_MENU1(), as the above code is very

    similar in layout to the actual code used in the construc-

    tion of LIST_MENU(), POP_MENU() and BAR_MENU() functions.

    The only additional sections required would be, additions

    to the CASE statement constants to pick up perhaps pgup,

    pgdn, <ctrl>+pgup and <ctrl>+pgdn keystrokes, a section

    to detect if the character key corresponding to the first

    character in a menu option has been pressed, and a further

    combined section to detect Return, Esc and any other keys

    you may require, and to send back the number of the option

    chosen via the "LIST_MENU1 := option number" Equation, to

    the user.

    As can be seen extensive use must be made of the newly

    defined menus record variables, this is true in many of

    the cases where the low level procedures are used.

    It would be well worth your while to take time to study

    the above example, along with all the new predefined

    data types, constants, records and variables, all of which

    are described in another section of this reference guide.

.PA

Š     This particular example serves to demonstrate the following

    procedures:- _MPLBAR_DO(), _MPLBAR_UP(), _MLMOV_DO() and

    _MLMOV_UP(). A 25 option list type menu will be displayed

    the user will be able to scroll the highlighted menu option

    bar up and down, using the keypad 8 and 2 keys respectively

    when the bar reaches the middle visible option, from either

    direction, the list will be scrolled in the opposite

    direction, the menu bar will always appear on the middle

    visible option, untill the topmost visible option is the

    topmost phisical option, moving up, or the bottommost

    visible option is the bottommost phisical opotion, moving

    down, when this condition is reached the menu bar will once

    again move over the options towards either the top or

    bottom of the menu.

.PA

Š      ------------------------------------------------------------------------

      _MLMOV_UP()                                                  _MLMOV_UP()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by LIST_MENU() to scroll or page

      Low Level     up through the options in a list menu, towards the top of

    the list, this procedure does not move the highlighted menu

    bar, it will remain in the same position.

    The scrolling can be either by a single menu option at a

    time or by a page at a time.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect any changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MLMOV_UP(ID,move);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than list menu the results could be

    unpredictable.


    move : char;

    This move character must be one of the four following

    characters 'S','s' or 'P','p' or its ascii value equivalent

    If 'S' is sent then the list will be scrolled downwards by

    one option only, moving us towards the top of the list,

    if the topmost visible option is already the topmost

    phisical option (top of list) then no action is taken.

    If 'P' is sent then the list will be paged downwards by the

    number of options visible on the screen, or the rows_vis

    value used in the call to LIST_MENU(), moving us towards

    the top of the list, if there is insufficient options left

    for a full page (rows left < rows_vis) then the remainder

    will be paged into view with the topmost phisical option

    in the list becoming the topmost visible option on the

    screen. if the topmost visible option is already the

    topmost phisical option (top of list) then no action is

    taken.

    If any character other than 'S' or 's' is recieved then it

    is assumed to be a 'P' or 'p', no checks are actually

    carried out to see if it is a 'P' or a 'p' so take care.


      Example     : Please refer to the _MLMOV_DO() procedure for the example.


      Rules Notes

      Tips & Traps: This procedure scrolls the options of a list menu up under

    the menu border, so that we are moving down towards the end

    of the phisical list.

.PA

Š     Move can be 'S' or 's' for scroll up one option, this does

    not preassume that the current row, ID^.row, is the bottom

    most option, thus allowing the options to scroll up with

    the highlighted bar anywhere on the menu, the menu bar is

    left in its original position.

    Move can be 'P' or 'p' for page up, ID^.rows_vis, scrolls

    up a page at a time, again no assumptions are made, thus

    allowing the options to scroll up with the highlighted bar

    anywhere on the menu, the menu bar is left in its original

    position.

    Please also refer to the _MLMOV_DO() procedure for further

    rules, notes, tips and traps.

.PA

Š      ------------------------------------------------------------------------

      _MPBAR_END()                                                _MPBAR_END()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by POP_MENU() to move the high-

      Low Level     lighted menu bar to the last/bottom option in a pop menu.

    No action is taken if the highlighted menu bar is already

    at the bottom of the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MPBAR_END(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop menu the results could be

    unpredictable.


      Example     : program MPBAR_END;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Move Bar To End';  {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Move Bar To End';  {*OPTION STRINGS        *}

       mt^[3] := 'Move Bar To End';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,15,10);

  case m1c of

     1..3 : _MPBAR_END(m1);  {*MOVE OPTION BAR TO END*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a pop menu only, to the bottom/last option. If the bar

    is found to be at the bottom already, no action is taken.

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open pop menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.                    

    The example will move the highlighted menu option bar to

    the end option each time options 1..3 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MPBAR_HOME()                                              _MPBAR_HOME()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by POP_MENU() to move the high-

      Low Level     lighted menu bar to the top/first option in a pop menu.

    No action is taken if the highlighted menu bar is already

    at the top of the menu.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MPBAR_HOME(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop menu the results could be

    unpredictable.


      Example     : program MPBAR_HOME;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Move Bar To Home'; {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Move Bar To Home'; {*OPTION STRINGS        *}

       mt^[3] := 'Move Bar To Home';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,15,10);

  case m1c of

     1..3 : _MPBAR_HOME(m1); {*MOVE OPTION BAR HOME*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a pop menu only, to the top/first option. If the bar

    is found to be at the top already, no action is taken.

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    menus. Using it on other menu types will trash the screen

    and put incorrect values into that menus record, possibly

    rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open pop menu only, not any other menu type or 

    a window, the result of doing this will possibly corrupt 

    the record or be unpredictable.  

    The example will move the highlighted menu option bar to

    the home option each time options 1..3 are chosen.        

.PA

Š      ------------------------------------------------------------------------

      _MPLBAR_DO()                                                _MPLBAR_DO()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by POP_MENU() to move the high-

      Low Level     lighted menu bar down by one option in a pop menu.

    If the highlighted menu bar is at the bottom of the menu

    the highlighted menu bar will be looped to the topmost

    option.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MPLBAR_DO(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop or list the results could be

    unpredictable.


      Example     : program MPLBAR_DO;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Go Down 1 Option'; {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu option 2';    {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,15,10);

  case m1c of

     1..3 : _MPLBAR_DO(m1);  {*MOVE OPTION BAR DOWN 1*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a pop or list menu only, down by one option. If the bar

    is found to be at the bottomost option already, the bar 

    will be looped back up to the topmost option.

.PA

Š     The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    and list menus. Using it on other menu types will trash

    the screen and put incorrect values into that menus record

    possibly rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open pop or list menu only, not any other menu 

    type or a window, the result of doing this will possibly

    corrupt the record or be unpredictable. 

    The example will move the highlighted menu option bar one

    option downwards each time options 1..3 are chosen.

.PA

Š      ------------------------------------------------------------------------

      _MPLBAR_OFF()                                              _MPLBAR_OFF()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by _MPLBAR_UP(), _MPLBAR_DO(),

      Low Level     _MPBAR_HOME() and _MPBAR_END(), _MLBAR_HOME(), _MLBAR_END() 

    to turn off the highlighted menu bar in a pop or list menu.

    The menu ID must have been previously created by using

    NEW_MENU().                                               

    The menus record is not affected by this command.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MPLBAR_OFF(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().                                          

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop or list the results could be

    unpredictable.


      Example     : program MPLBAR_OFF;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                 {*DEF OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);               {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Turn Bar Off';      {*MEM AND DEFINE MENU*}

       mt^[2] := 'Menu Option 2';     {*OPTION STRINGS     *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);              {*RECLAIM MEMORY AND  *}

       m1c := 10;                     {*DELETE POINTER TO IT*}

       while (m1c <> 0) do            {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,10,10);

  case m1c of

     1 : _MPLBAR_OFF(m1);       {*TURN OPTION BAR OFF*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure turns off a highlighted menu bar on a pop

    or list menu, by redrawing it in its normal attributes, 

    It does this by taking the character word, which is in

    screen ram format, directly from the mmenu word array, so 

    if any characters in the option have been changed using the

.PA

Š     MCHANGE_CHAR() procedure, they will still be displayed in

    there changed format, re:- the MCHANGE_CHAR() procedure.

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    and list menus. Using it on other menu types will trash 

    the screen and put incorrect values into that menus record 

    possibly rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open pop or list menu only, not any other menu 

    type or a window, the result of doing this will possibly 

    corrupt the record or be unpredictable.                   

    The example will turn off the highlighted menu option bar

    each time option 1 is chosen.                             

.PA

Š      ------------------------------------------------------------------------

      _MPLBAR_ON()                                                _MPLBAR_ON()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by _MPLBAR_UP(), _MPLBAR_DO(),

      Low Level     _MPBAR_HOME() and _MPBAR_END(), _MLMOV_UP(), _MLMOV_DO(),

    _MLBAR_TLST(), _MLBAR_BLST(), _MLBAR_HOME(), _MLBAR_END()  

    to turn on the highlighted menu bar in a pop or list menu.

    The menu ID must have been previously created by using

    NEW_MENU().                                               

    The menus record is not affected by this command.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _MPLBAR_ON(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().                                          

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop or list the results could be

    unpredictable.


      Example     : program MBAR_ON;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                 {*DEF OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);               {*DYNAMICALY ALLOC   *}

       mt^[1] := 'Turn Bar On';       {*MEM AND DEFINE MENU*}

       mt^[2] := 'Bar Off';           {*OPTION STRINGS     *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);              {*RECLAIM MEMORY AND  *}

       m1c := 10;                     {*DELETE POINTER TO IT*}

       while (m1c <> 0) do            {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,10,10);

  case m1c of

     1 : _MPLBAR_ON(m1);      {*TURN OPTION BAR ON*}

     2 : _MPLBAR_OFF(m1);     {*TURN OPTION BAR OFF*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure turns on a highlighted menu bar on a pop

    or list menu, this is achieved by changing the screen ram

    character word's colour byte, using this ID's original 

.PA

Š     "tbc" and "tfc" complemented colours, which were calculated 

    from the specified "tb" and "tf" colours in the call to 

    NEW_MENU(), rather than using the colour values already in 

    the mmenu character word array and complementing them, as 

    they may be poor colours for complementing, provided the 

    original "tb" and "tf" colours were well chosen, this will 

    ensure that the highlighted option will always be visible, 

    regardles of how individual characters may have been 

    changed using the MCHANGE_CHAR() procedure.

    The pick (first) character will always appear in its

    originally defined colour "pc", even when highlighted,

    unless changed with MCHANGE_CHAR(). 

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    and list menus. Using it on other menu types will trash 

    the screen and put incorrect values into that menus record 

    possibly rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is

    for a valid open pop or list menu only, not any other menu 

    type or a window, the result of doing this will possibly 

    corrupt the record or be unpredictable.

    The example will turn on the highlighted menu option bar

    each time option 1 is chosen, and off when option 2 is

    chosen.                                                   

.PA

Š      ------------------------------------------------------------------------

      _MPLBAR_UP()                                                _MPLBAR_UP()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by POP_MENU() and LIST_MENU() to 

      Low Level     move the highlighted menu bar up by one option in a pop or

    list menu.

    If the highlighted menu bar is at the top of the menu the

    highlighted menu bar will be looped to the bottommost

    option.

    The menu ID must have been previously created by using

    NEW_MENU().

    The menus record is updated to reflect the changes.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.


      Syntax      : _MPLBAR_UP(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not exist or the ID belongs to a window or

    a menu type other than pop or list the results could be

    unpredictable.


      Example     : program MPLBAR_UP;

    uses dos,crt,winmen;

    var

       mt : pt_mtext;                {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;

    begin

       getmem(mt,3*81);              {*DYNAMICALY ALLOCATE   *}

       mt^[1] := 'Go Up 1 Option';   {*MEMORY AND DEFINE MENU*}

       mt^[2] := 'Menu option 2';    {*OPTION STRINGS        *}

       mt^[3] := 'Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);             {*RECLAIM MEMORY AND  *}

       m1c := 10;                    {*DELETE POINTER TO IT*}

       while (m1c <> 0) do           {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,15,10);

  case m1c of

     1..3 : _MPLBAR_UP(m1);  {*MOVE OPTION BAR DOWN 1*}

  end;

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: This procedure will move the highlighted menu option bar

    on a pop or list menu only, up by one option. If the bar

    is found to be at the topmost option already, the bar will 

.PA

Š     be looped on down to the bottommost option.

    The procedure achieves its speed by using direct screen

    ram access techniques, to place characters directly into

    screen ram.

    The procedure will only work correctly when used on pop

    and list menus. Using it on other menu types will trash the

    screen and put incorrect values into that menus record, 

    possibly rendering it useless.

    Being a low level procedure no checks are carried out on

    any data passed to it by the user, so make sure the ID is 

    for a valid open pop or list menu only, not any other menu 

    type or a window, the result of doing this will possibly

    corrupt the record or be unpredictable. 

    The example will move the highlighted menu option bar one

    option upwards each time options 1..3 are chosen.

.PA

Š












      WINDOWS AND MENUS FOR TURBO PASCAL

      ----------------||----------------

      COMMON FUNCTIONS REFERENCE SECTION

.PA

Š      ------------------------------------------------------------------------

      _WMCHK_FOR_MREC()                                      _WMCHK_FOR_MREC()

      ------------------------------------------------------------------------ 


      Function    : Check to make sure that a maprec exists, for the object

      Low Level     specified by ID, by checking the 3D screen map at the

    map_inx location corresponding to the top left corner

    position of the object ID on the screen. 

       The function calculates map_inx its self, by using the 

    objects "l,t,r,b" values, from the objects wmrec.

       Only the linked list at location map_inx is checked, 

    this is sufficient, under normal circumstances, to prove 

    weather a complete maprec structure for the specified 

    object ID exists or not.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       No checks are carried out on the validity of data 

    supplied to this low level function, so extra care is 

    needed.

       The objects wmrec is not affected by this function.  

       This function is called by:- WMADD_MREC_ALL(); 

    WMFLOAT(); WMDEL_MREC_ALL(); WMREMOVE(); WMSAVE_SCR();


      Syntax      : result := _WMCHK_FOR_MREC(ID)


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the results will be 

    unpredictable, as the ID is not checked.                   


    result : boolean;

    The function will return TRUE if a maprec does exist for

    the specified object,at the map_inx location corresponding 

    to the top left corner position of the the object ID on 

    the screen, and FALSE if not.


      Example     : procedure _DELRECS1(ID);

    var

       ncol,nrow : byte;

       mapinx,map_inx,sc_inx : word;

       IDWM : pt_wmrec;

    begin

       if(_WMCHK_FOR_MREC(ID) = false) then;

                       begiî                          {*CHK STRUCTURE EXISTS*}

                          could print a message;

                          exit or halt;

                       end;

.PA

Š        IDWM := ID_WM[IDB];            {*GET POINTER TO WMREC*} 

       nrow := num rows in object     {*CALC ROWS & COLS*}     

       ncol := num cols in object      

       mapinx := top left char posn   {*CALC MAP ARRAY INDEX*} 

       sc_inx := 0;                   {*W/M SCREEN ARRAY INX*} 


       for each row in object do      {*FOR EACH ROW IN OBJ*}

       begin

  map_inx := mapinx;          {*UPDATE MAP COL INDEX*} 

  for each column in row do   {*FOR EACH COL IN ROW*}

  begin                       {*ADD A RECORD TO MAP*}

     _WMDEL_MREC(ID,map_inx);

     inc map_inx to next column{*INC MAP ROW INDEX*}

     inc sc_inx to next column{*INC OBJ SCR ARY INX*}

  end;                        {*INC TO NEXT ROW*}

  inc mapinx to start of next row

       end;

    end {_DELRECS1};


      Rules Notes

      Tips & Traps: The above example, in a mixture of Pascal and psuedo code,

    shows how to delete a complete maprec structure from the

    3D screen map, for any given object (window, menu or user 

    screen). 

       The example, in common with any of the Windows and 

    Menus low level routines, does not carry out any checking 

    on the parameters supplied to it by the user, so if, for 

    instance, an invalid object ID was supplied, there would 

    almost certainly be a fatal error during the 

    _WMCHK_FOR_MREC(); function, as pointer chasing is carried 

    out, this would result in the routine hanging the system.  

    This type of basic ID check, along with other checks, 

    would normaly be carried out in a high level type of 

    routine, prior to a low level call. This checking routine 

    does however provide the maprec creating and deleting 

    procedures with complete safety, provided it is passed a 

    valid ID. That is an ID for any OPEN menu, open or closed 

    window or user screen. As the wmrec "l,t,r,b" fields, 

    that it uses, become available at diferent times, 

    depending on the object type,(see section on wmrec types).

       As with any routine that uses pointers and allocates or 

    deallocates memory, as does _WMCHKL_FOR_MREC(); great care 

    needs to be taken and in particular checks needs to be 

    carried out prior to its use.

.PA

Š      ------------------------------------------------------------------------

      _WMSAVE_SCR()                                              _WMSAVE_SCR()

      ------------------------------------------------------------------------ 


      Function    : Save the area of screen bounded by the supplied l,t,r,b

      Low Level     values into an array of type "screen" and return a 

    pointer to it.  

       For details of the "screen" type, which is a Winmen 

    declared data type, see the section titled "Winmen 

    Declared Types", in chapter 2. 

       If there is insufficient contigious memory left to 

    allocate for the save, the programme will be aborted with 

    an error message, (see appendix for list).

       This procedure does not link the area of screen being

    saved into the 3D screen MAP[] system, if this is what you

    intened to do then please refer to the WMSAVE_SCR();

    procedure and the sub-section on "maprecs" in the "Winmen

    Declared Types" section.

       No other checks are carried out on the validity of data

    supplied to this low level function, so extra care is 

    needed.

       The objects wmrec is not affected by this function.  

       This function is called by:- WMMOVE(); and WMOPEN();


      Syntax      : my_area := _WMSAVE_SCR(l,r,t,b)


      Variables   : l : byte; (B1_80)

    Leftmost edge of the screen area to be saved, must be a 

    value between 1-80 or a range check error will occure.

 

                    t : byte; (B1_25)

    Topmost edge of the screen area to be saved, must be a 

    value between 1-25 or a range check error will occure.

 

                    r : byte; (B1_80)

    Rightmost edge of the screen area to be saved, must be a 

    value between 1-80 or a range check error will occure.


                    b : byte; (B1_25)

    Bottommost edge of the screen area to be saved, must be a 

    value between 1-25 or a range check error will occure.

      

    my_area : pt_scr;

                    This is the pointer value returned by the function and is

    the starting address of the block of memory allocated to

    hold the screen area bounded by the supplied l,t,r,b

    values. The area is stored in screen ram format.

       For a full explanation of the "pt_scr" type refer to

    section titled "Winmen Declared Types" in chapter one.

.PA

Š      Example     : program _WMSAVSC;


    uses crt,dos,winmen;


    var

       my_area : pt_scr;


    begin                             {*WRITE SOME TEXT*}

       clrscr;

       writeln('We will put a few lines of text');

       writeln('on the screen so we can copy the');

       writeln('screen to another position.');

       my_area := _WMSAVE_SCR(1,1,32,3);

       gotoxy(1,9);                   {*SAVE SCREEN AREA*}

       write('<RET> key to copy area2 = area1, wid/hgt same');

       readln;

       _WMREST_SCR(my_area,35,19,66,21);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to copy area2 > area1....');

       readln;

       _WMREST_SCR(my_area,35,2,75,6);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to copy area2 = area1, wid/hgt not =');

       readln;

       _WMREST_SCR(my_area,4,18,15,25);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to continue....');

       readln;

    end.


      Rules Notes

      Tips & Traps: The example will effectively copy the area of screen

                    bounded by 1,1,32,3 to the new area 35,15,67,17. In this

    example the two areas have exactly the same width and

    height, it is important that the area you restore is the

    exact same size as the one you saved, although you could

    of course specify a diferent width and or height, as long

    as area1 = area2. If area2 is < area1 then no harm will

    come, you will just get less of the original text in the

    new position. As the "screen" array type that "pt_scr"

    points to is a linear array, it will be the later part of

    the text that will be missing. If area2 is > area1 the

    extra (area2-area1) that will be restored will just be

    whatever data exists in memory above the block reserved

    for the "my_area" screen array, probably rubbish.

.PA

Š












     WINDOWS AND MENUS FOR TURBO PASCAL

     -----------------||----------------

     COMMON PROCEDURES REFERENCE SECTION

.PA

Š      ------------------------------------------------------------------------

      WMADD_MREC_ALL()                                        WMADD_MREC_ALL()

      ------------------------------------------------------------------------ 


      Procedure   : Add a complete maprec structure into the 3D screen map

      High Level    for the object specified by ID. This procedure adds a 

    new maprec, for each character position, in the object, 

    to the end of each appropriate linked list in the 3D

    screen map.

       If the object is closed, or a maprec already exists at

    the map_inx position corresponding to the top left hand

    corner of the open object on the screen, then no action is

    taken and the procedure exits, as closed objects are never

    linked into the Winmen 3D screen map system and if

    "maprecs" already exist for an object we do not want to

    double up, as this may prove disasterous.

       If there is insufficient contigious memory left to

    allocate for all the new maprec's required, for the object 

    specified by ID, then the programme will abort with an 

    error message (see appendix for list).

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().

       The objects wmrec is not affected by this procedure

       This procedure is also called by:- WMMOVE(); 

    WMSAVE_SCR(); WOPEN(); 

       This procedure is NOT called by WMSLIDE(); refer to

    the WMSLIDE(); procedure for more information.


      Syntax      : WMADD_MREC_ALL(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the programme will abort 

    with an error message (see appendix for list).


      Example     : program ADD_MR_A;


    uses dos,crt,winmen;


    var

       w1,w2 : byte;

.PA

Š     begin                             {*DEFINE WINDOWS*}  

       w1 := NEW_WIN(1,8,25,14,1,7,0,0,3);   

       w2 := NEW_WIN(40,4,70,10,4,1,14,0,14);

       WOPEN(w1);                     {*OPEN WINDOWS*}

       WOPEN(w2);

       delay(750);

       WMDEL_MREC_ALL(w1);            {*DELETE ALL MRECS FOR*}

       WMSLIDE(w1,'r',30);            {*OBJECT BEFORE SLIDE*}

       WMADD_MREC_ALL(w1);            {*RE-CREATE AFTERWARDS*}

       delay(750);

       WMFLOAT(w2);                   {*FLOAT W2 TO PROVE   *}

       delay(750);                    {*THE MRECS WERE ADDED*}

       WMFLOAT(w1);                   {*PUT W1 BACK ON TOP*}

       delay(750);

       WMDELETE(w2);                  {*DELETE BOTH WINDOWS*}

       delay(750);

       WMDELETE(w1);

    end.


      Rules Notes

      Tips & Traps: The above example simply opens two windows then slides 

    the first one along to overlap the second one, the second 

    one is then floated to the top, then the first one is 

    floated to the top, the second one is then deleted, then 

    the first. 

       The purpose of all this is to demonstrate where the 

    WMADD_MREC_ALL(); and WMDEL_MREC_ALL(); procedures can or

    must be used.  Firstly, the WMSLIDE(); procedure does not 

    unlink, or relink, the object currently being slid, from 

    and to the 3D screen map, this is left to the user to do 

    manualy.

       The WMSLIDE(); procedure is the only routine that does

    not call either WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); out 

    of all the routines that may need to do so.

       The WMSLIDE(); and WSELECT(); procedures are the only 

    routines that do not call WMFLOAT(); out of all the 

    routines that may need to do so.

       The reasons for this are as follows:-

       You may, for instance, want to slide an object in more 

    than one direction in two consecutive calls to WMSLIDE(); 

    if the WMSLIDE();procedure were to delete and add maprec's 

    and call WMFLOAT(); for you, each time it was called, we 

    would get a time lag at the start and end of each call, 

    while the object was floated and maprec's were deleted 

    from the objects old position and then added to the 

    objects new position in the 3D screen map, although this 

    lag is only very very small, it is enough to introduce a 

    jerk into what is otherwise a perfectly smooth sliding 

    action.  Dont forget we only want the object, currently 

    being slid, to be linked into the 3D screen map in its 

    final resting place.  All other maprec's belonging to that 

    object must be deleted, if they are not they will cause 

    unpredictable behavior, possibly resulting in a trashed 

    screen, or even a crash.

.PA

Š        On the other hand you may want to write to more than 

    one window at once, or at least, make it appear as if you 

    are. This can only be done by first selecting the window 

    to write to, using WSELECT(); then actualy writing to it. 

    If the WSELECT(); procedure had to call WMFLOAT() each 

    time it was called, this would slow things down 

    considerably and spoil our illusion, besides the windows 

    that you are writing to may all be fully visible, in 

    which case there is no need to float them to the surface 

    before writing to them. if they are obscured and you dont

    want to make use of the WWRITE(); or WWRITELN(); 

    procedures, to write text to a window in the background, 

    then you will have to call WMFLOAT(); either before or 

    after calling WSELECT(); and prior to writing to each 

    window. So as you can see the choice is best left up to 

    the user, for maximum flexibility.

.PA

Š      ------------------------------------------------------------------------

      WMATTRIBS()                                                  WMATTRIBS()

      ------------------------------------------------------------------------


      Procedure   : Change the attributes associated with a window, menu or a

      High Level    user saved screen area ID (saved using WMSAVE_SCR()), to 

    those in the supplied list. The change will be permenant or

    untill changed again using this procedure or WCOLOUR() for 

    a window or user saved screen or _WMBOX_ATTRIBS(), for a 

    window or menu.  

    The window or menu ID must have been previously created by 

    using NEW_WINDOW() or NEW_MENU().

    The window or menus record is updated to reflect the 

    changes.        


      Syntax      : WMATTRIBS(ID,btype,bb,bf,tb,tf);


      Variables   : ID : byte;

    The unique identifier for the specified menu as returned

    from NEW_MENU().

    If the ID does not yet exist the programme will abort with 

    an error message (see appendix for list).


    btype : byte; (B1_4)

    Type of border required around the menu edge, must be a

    value between 1-4 or a range check error will occure.

    The possible border types are as follows:-

       1 = Double horizontal and double vertical bars.

       2 = Single horizontal and single vertical bars.

       3 = Double horizontal and single vertical bars.

       4 = Single horizontal and double vertical bars.


    bb : byte; (B0_15)

    Border background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    bf : byte; (B0_15)

    Border foregroung colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tb : byte; (B0_15)

    Text background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    tf : byte; (B0_15)

    Text foreground colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).

.PA

Š   CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink


      Example     : program WMATTRIB;


    uses dos,crt,winmen;


    var

       mt : pt_mtext;              {*DEFINE OPTION TEXT PTR*}

       m1 : byte;

       m1c : word;


    begin

       getmem(mt,3*81);                 {*DYNAMICALY ALLOC   *}

       mt^[1] := '1) Change Attribs';   {*MEMORY AND DEF MENU*}

       mt^[2] := '2) Change Pic Colour';{*OPTION STRINGS     *}

       mt^[3] := '3) Menu Option 3';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,3); {*CREATE MENU*}

       freemem(mt,3*81);           {*RECLAIM MEMORY AND  *}

       m1c := 10;                  {*DELETE POINTER TO IT*}

       while (m1c <> 0) do         {*USE THE MENU*}

       begin

  m1c := POP_MENU(m1,5,5);

  case m1c of              {*RANDOMLY CHANGE ATTRIBS*}

     1 : WMATTRIBS(m1,random(4),random(15),

    random(15),random(15),random(15));

     2 : WMPIC_COL(m1,random(15));

  end;                     {*RANDOMLY CHANGE PIC COL*}

  WMCLOSE(m1);

       end;

       normvideo;

    end.


      Rules Notes

      Tips & Traps: The attributes changeable by this procedure are the border

    type, border and text background and foreground colours.

    The menu option pic character (first character) can be

.PA

Š     changed using the MPIC_COL() procedure.

    Both the window or menus record variables are updated to

    reflect the changes, all the colour attributes are changed

    bb,bf,tb,tf, and the calculated values tbc and tfc.

    If the ID belongs to a menu then the menus mmenu screen ram

    format array is also updated with the changes.

    Any changes made will become effective:-

    a) The next time a window is written to,if it is the active

       one, for tb and tf.

    b) The next time a window is selected for use, and written

       to, if it is a non-active one, for tb and tf.

    c) The next time a window or menu is opened for use, for

       btype,bb,bf,tb,tf and the calculated values tbc and tfc.

    This procedure may also be used on user saved screen areas

    (saved using WMSAVE_SCR()), although only the tb and tf

    values will have any affect, as there is no border. Again

    the changes will become effective the next time that ID

    screen area is written to.

    Any window, menu or user screen area, open, closed, active 

    or not active can have its attributes changed ready for the

    next time it is used.

.PA

Š      ------------------------------------------------------------------------

      WMCLOSE()                                                      WMCLOSE()

      ------------------------------------------------------------------------


      Procedure   : Close the window, menu or user saved screen area,

      High Level    associated with ID, and restore the screen behind it, such

    that it is visually correct, regardless of weather the

    object in question is partially, or fully obscured, or

    not obscured at all, by other objects.

       This system switch gives the user two diferent methods

    of closing objects and removing them from the screen, they

    are:-


       CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface with WMFLOAT()

       and then restoring the objects ID_SC[] background

       screen array using WMREST_SCR(); to effectively remove

       them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.


       Any object, that for some reason, does not have any

    "maprecs" linking it into the Winmen 3D screen map system,

    can not be WMFLOATed or WMREMOVEd, depending on the system

    switch above, as both these routines will exit, with no

    action, if no "maprecs" exist for the object in question.

    The object will however still be closed, by WMCLOSE(); but

    using just the WMREST_SCR(); procedure as its main effort.

       WARNING... If the WMCLOSE() procedure reveals that no

    "maprecs" exist, for the object, at the appropriate 3D

    screen map locations, then it is forced to make the

    assumption that the object is not obscured by any other

    object, as no other facts are available to it, so a close

    by using WMREST_SCR(); to restore the objects ID_SC[]

    background screen array should be sufficient. If the

    object is obscured by others, either partially or fully,

    then you can expect some display corruption at some stage,

    possibly sooner rather than later.

       After closing, the window or user screens text cursor,

    used by the WWRITE(); and WWRITELN(); procedures only, is

    positioned at x1,y1 which is the top left most corner of a

    user screen and excluding the border for a window.

       The Winmen window/user text cursor can be repositioned

    using the WGOTOXY(); procedure, it has no effect at all on

    the Turbo Pascal text cursor, which is used with the

    standard Turbo Pascal write(); and read(); procedures and

    positioned with gotoxy().

.PA

Š        The window, menu or user screen ID must have been

    previously created by using NEW_WINDOW(), NEW_MENU() or

    WMSAVE_SCR(); respectively and opened for use with one of

    the appropriate window/user or menu functions and/or

    procedures.

       This procedure is also called by WMDELETE().

       The window, menu or user screen record is updated to

    reflect the changes.


      Syntax      : WMCLOSE(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a 

    user saved screen area.

    If the ID does not yet exist the programme will abort with 

    an error message (see appendix for list).                 


      Example     : program WM_CLOSE;


    uses dos,crt,winmen;


    var

       ID,c,cpx,cpy : byte;     {*DEFINE VARIABLES*}

       W1 : pt_wmrec;


    begin                       {*CREATE WINDOW*}  

       ID := NEW_WIN(1,1,15,5,1,1,14,7,0);

       W1 := ID_WM[ID];

       for c := 1 to 20 do      {*MOVE WINDOW DIAGONALLY*}

       begin

  WOPEN(ID);

  delay(250);           {*DELAY TO SMOOTH OUT*}

  WMCLOSE(ID);          {*INCREMENT WINDOW PARAMETERS*}

  inc(W1^.l,3);         {*IN WINDOW RECORD, ALL THESE*}

  inc(W1^.r,3);         {*NEED TO BE MODIFIED TO MOVE*}

  inc(W1^.t);           {*A WINDOWS POSITION AND THEN*}

  inc(W1^.b);           {*OPEN IT IN ANOTHER POSITION*}


  cpx := ((W1^.r-W1^.l) div 2)+W1^.l;

  cpy := ((W1^.b-W1^.t) div 2)+W1^.t;

  W1^.cp := ((((cpy-1)*80)+cpx)*2)-2;

  W1^.lt := cpx-1;

  W1^.tt := cpy-1;

  W1^.rt := cpx+1;

  W1^.bt := cpy+1;

       end;

       WMDELETE(ID);            {*DELETE THE WINDOW REC ETC*}

       normvideo;

    end.                                                        

.PA

Š      Rules Notes

      Tips & Traps: Closing a non active window does not affect the currency

    of the active window, for example if the currently active

    window is closed then the new active window effectively

    becomes the full screen, so any write operations will now

    go to the normal full screen, if a non active window is

    closed the active window remains the one currently in use.

       Closing a window, menu or user saved screen area is not

    the same as deleting it, closing it does not release any

    of the memory being used by it, ie. The objects "wmrec"

    record, background "screen" array, "mmenu" array, or a bar

    menus ID_MC[] comment array, if one exists, everything is

    left intact, including the "ID", which is the only link

    the user has with that particular window, menu or user

    saved screen area, this is so that it may be used again

       If you are finished with that window, menu or user

    saved screen area for good, then to reclaim the memory

    space occupied by it you will need to use the WMDELETE()

    procedure.

       However, closing an object will result in it being

    completely removed from the 3D screen map system, as the

    3D screen map is only interested in objects that are

    open on the screen. This is done by deleting all of the

    objects "maprec" records from the 3D screen map, if for

    some reason no "maprecs" exist for the object in

    question then no harm will come, as WMCLOSE(); checks

    this first and makes no attempt to delete "maprecs" that

    do not exist. For more detailed information on the 3D

    screen map system, refer to the "maprec" type in the

    section "Winmen Declared Types".

       The example will open, close and move the window, then

    repeat the cycle 20 times, moving the window diagonally,

    this shows how you could construct a MOVE type procedure.

       Any window, menu or USER saved screen area that has a

    title will loose the title when it is closed using the

    WMCLOSE() procedure, this is so that you can have a

    titleless window menu or USER saved screen, each time it

    is opened, of course there are thoes that will say the

    titles ought to be retained, for windows and USER saved

    screens this is not possible as they are generated each

    time they are opened, they do not have a permenant array

    like the mmenu array for menus, and to have one would take

    up much more valuable memory space, so there is nowhere to

    put the title, menus could conceivably retain there titles

    by removing the code which deletes them from the WMCLOSE()

    procedure, the only problem then would be deleting a title

    if one were not required, we would need to send a string

    of that menus border type chars each time we wanted to

    delete a title.

.PA

Š      ------------------------------------------------------------------------

      WMDELETE()                                                    WMDELETE()

      ------------------------------------------------------------------------


      Procedure   : Delete a window, menu or user saved screen area (saved

      High Level    using WMSAVE_SCR();), by returning all memory allocated

    to that particular ID to the heap and NILing all the 

    pointers associated with it. This allows that particular

    ID reference to be reused, in a subsequent call to either

    NEW_WIN(); NEW_MENU(); or WMSAVE_SCR(0-19);

       Deleting the window, menu or user saved screen area,

    associated with ID, will restore the screen behind it,

    such that it is visually correct, regardless of weather

    the object in question is partially, or fully obscured, or

    not obscured at all, by other objects.

       If the window, menu or user saved screen area is open

    it will first be closed with WMCLOSE();

       This system switch gives the user two diferent methods

    of deleting objects and removing them from the screen, they

    are:-


       CLOSE_WITH_REMOVE := false; All objects will be deleted

       by firstly floating them to the surface and then

       restoring the objects ID_SC[] background screen array,

       to effectively remove them.

       CLOSE_WITH_REMOVE := true; All objects will be deleted

       by firstly using the WMREMOVE(); procedure,this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.


       Please refer to the WMCLOSE(); procedure and the

    section "Winmen Declared Types" for more information.

       The ID returned from NEW_WIN(); and NEW_MENU(); or the

    one used in the calls to WMSAVE_SCR(0-19); is unlinked

    from its memory area pointers, thus a structure such as

    this once deleted is not recoverable, so use with care.

       Deleting an object will result in it being completely

    removed from the 3D screen map system, as the 3D screen

    map is only interested in objects that are open on the

    screen.  This is done by deleting all of the objects

    "maprec" records from the 3D screen map, if for some

    reason no "maprecs" exist for the object in question then

    no harm will come, as WMDELETE(); checks this first and

    makes no attempt to delete "maprecs" that do not exist.

    For more detailed information on the 3D screen map system,

    refer to the "maprec" type in the section "Winmen Declared

    Types".

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).

       This procedure is not called by any of the functions

    or procedures in the Winmen Unit.

.PA

Š      Syntax      : WMDELETE(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a 

    user saved screen area.

    If the ID does not yet exist the programme will abort with 

    an error message (see appendix for list).                 


      Example     : program WM_DELETE;

    uses dos,crt,winmen;

    var

       ID : byte;

    begin

       ID := NEW_WIN(5,5,50,20,1,1,14,7,0);

       WOPEN(ID);

       write(scr,'Press Return To DELETE The Window');

       readln;

       WMDELETE(ID);

       normvideo;

    end.   


      Rules Notes

      Tips & traps: If you find you have run out of available window/menu ID

    references, and have windows or menus that you no longer

    require, you should use WMDELETE() to reclaim all that

    valuable memory, this will also free up that ID, allowing

    you to once again create another window or menu, using

    NEW_WINDOW() or NEW_MENU(). Although this is a most

    unlikely situation, as you will almost certainly run out

    of memory before ID's, depending on the size of each

    window or menu.

       The example just creates a window then deletes it when

    the user presses the return key.

.PA

Š      ------------------------------------------------------------------------

      WMDEL_MREC_ALL()                                        WMDEL_MREC_ALL()

      ------------------------------------------------------------------------ 


      Procedure   : Delete a complete maprec structure from the 3D screen map

      High Level    for the object specified by ID. This procedure deletes a 

    maprec, for each character position, in the object, from 

    the end of each appropriate linked list in the 3D screen 

    map. 

       If the object is closed, or no maprec exists at the 

    map_inx position corresponding to the top left hand corner 

    of the object on the screen, then no action is taken and 

    the procedure exits.

       Once all the maprec's, for the specified object, have 

    been deleted, the memory occupied by them is returned to 

    the heap for reuse.  

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().

       The objects wmrec is not affected by this procedure

       This procedure is also called by:- WMMOVE(); WMCLOSE(); 

    WMREMOVE();

       This procedure is NOT called by WMSLIDE();


      Syntax      : WMDEL_MREC_ALL(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the programme will abort 

    with an error message (see appendix for list).


      Example     : program DEL_MR_A;


    uses dos,crt,winmen;


    var

       w1,w2 : byte;

.PA

Š     begin                             {*DEFINE WINDOWS*}  

       w1 := NEW_WIN(1,8,25,14,1,7,0,0,3);   

       w2 := NEW_WIN(40,4,70,10,4,1,14,0,14);

       WOPEN(w1);                     {*OPEN WINDOWS*}

       WOPEN(w2);

       delay(750);

       WMDEL_MREC_ALL(w1);            {*DELETE ALL MRECS FOR*}

       WMSLIDE(w1,'r',30);            {*OBJECT BEFORE SLIDE*}

       WMADD_MREC_ALL(w1);            {*RE-CREATE AFTERWARDS*}

       delay(750);

       WMFLOAT(w2);                   {*FLOAT W2 TO PROVE   *}

       delay(750);                    {*THE MRECS WERE ADDED*}

       WMFLOAT(w1);                   {*PUT W1 BACK ON TOP*}

       delay(750);

       WMDELETE(w2);                  {*DELETE BOTH WINDOWS*}

       delay(750);

       WMDELETE(w1);

    end.


      Rules Notes

      Tips & Traps: The above example simply opens two windows then slides 

    the first one along to overlap the second one, the second 

    one is then floated to the top, then the first one is 

    floated to the top, the second one is then deleted, then 

    the first. 

       The purpose of all this is to demonstrate where the 

    WMADD_MREC_ALL(); and WMDEL_MREC_ALL(); procedures can or

    must be used.  Firstly, the WMSLIDE(); procedure does not 

    unlink, or relink, the object currently being slid, from 

    and to the 3D screen map, this is left to the user to do 

    manualy.

       The WMSLIDE(); procedure is the only routine that does 

    not call either WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); out 

    of all the routines that may need to do so.

       The WMSLIDE(); and WSELECT(); procedures are the only 

    routines that do not call WMFLOAT(); out of all the 

    routines that may need to do so.

       The reasons for this are as follows:-

       You may, for instance, want to slide an object in more 

    than one direction in two consecutive calls to WMSLIDE(); 

    if the WMSLIDE();procedure were to delete and add maprec's 

    and call WMFLOAT(); for you, each time it was called, we 

    would get a time lag at the start and end of each call, 

    while the object was floated and maprec's were deleted 

    from the objects old position and then added to the 

    objects new position in the 3D screen map, although this 

    lag is only very very small, it is enough to introduce a 

    jerk into what is otherwise a perfectly smooth sliding 

    action.  Dont forget we only want the object, currently 

    being slid, to be linked into the 3D screen map in its 

    final resting place.  All other maprec's belonging to that 

    object must be deleted, if they are not they will cause 

    unpredictable behavior, possibly resulting in a trashed 

    screen, or even a crash.

.PA

Š        On the other hand you may want to write to more than 

    one window at once, or at least, make it appear as if you 

    are. This can only be done by first selecting the window 

    to write to, using WSELECT(); then actualy writing to it. 

    If the WSELECT(); procedure had to call WMFLOAT() each 

    time it was called, this would slow things down 

    considerably and spoil our illusion, besides the windows 

    that you are writing to may all be fully visible, in 

    which case there is no need to float them to the surface 

    before writing to them.  if they are obscured and you dont 

    want to make use of the WWRITE(); or WWRITELN(); 

    procedures, to write text to a window in the background, 

    then you will have to call WMFLOAT(); either before or 

    after calling WSELECT(); and prior to writing to each 

    window. So as you can see the choice is best left up to 

    the user, for maximum flexibility.    

.PA

Š      ------------------------------------------------------------------------

      WMFLOAT()                                                      WMFLOAT()

      ------------------------------------------------------------------------ 


      Procedure   : Bring to the surface, by floating, the object specified 

      High Level    by ID. 

       By bringing to the surface we mean, put that object on 

    top of the pile and make it wholy visible to the user, 

    this includes any contents that a window or user screen 

    might have had.

       If the object is closed and it is a window or user 

    screen (ID < 20) then it will be opened, there will be no 

    need to float it, the objects wmrec will be updated to 

    reflect the change.

       If the object is closed and it is a menu, the 

    programme will be halted with an error message, as menus 

    can not be opened from within the WMFLOAT(); procedure 

    (see appendix for list).  

       If no maprec exists for the object at the map_inx 

    position corresponding to the top left hand corner of the 

    object on the screen, then no action is taken and the 

    procedure exits, it will not be floated.

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().

       The objects wmrec is not affected by this procedure

       This procedure is also called by:- WMMOVE(); WMCLOSE(); 

       This procedure is NOT called by WMSLIDE();              


      Syntax      : WMFLOAT(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the programme will abort 

    with an error message (see appendix for list).             


      Example     : program WM_FLOAT;


    uses dos,crt,winmen;


    var

       w1,w2,w3,w4,w5,w6,c,c1 : byte;


    begin                             {*DEFINE WINDOWS*}

       w1 := NEW_WIN(1,8,25,14,1,7,0,2,3);   

       w2 := NEW_WIN(40,4,70,10,4,1,14,3,14);                   

       w3 := NEW_WIN(10,6,48,17,2,2,3,1,9);                     

       w4 := NEW_WIN(28,14,65,23,3,4,6,2,11);                     

       w5 := NEW_WIN(1,16,40,25,1,0,15,0,13);                     

       w6 := NEW_WIN(15,15,68,18,2,4,1,5,1);                     

.PA

Š        for c := w1 to w6 do           {*OPEN WINDOWS*}

  WOPEN(c);


       for c := w1 to w6 do           {*FLOAT & WRITE*}

       begin

  WMFLOAT(c);

  WSELECT(c);

  write('This Window Is Well And Truely Open');

  delay(750);

       end;


       for c := 1 to 10 do            {*FLOAT WINDOWS*}

  for c1 := w1 to w6 do

  begin

     WMFLOAT(c1);

     delay(750);

  end;


       for c := w1 to w6 do           {*DELETE WINDOWS*} 

       begin                                             

  WMDELETE(c);                                   

  delay(750);                                    

       end;                                              

    end.                                                 


      Rules Notes

      Tips & Traps: The above example demonstrates the power of the 

    WMFLOAT(); procedure, by showing just how simple it is 

    to use it.      

       You should not experience any problems when using 

    this procedure, as it has been tried and tested over a 

    long period.  

       Being a high level routine numerous checks are carried 

    out on any parameters and data supplied to, or used by, 

    this routine.  The checking is carried out by the Winmen 

    Unit its self and include all the necassary checks on the 

    3D screen map, to ensure its integrity.  This procedure, 

    as with all other high level routines, in the Winmen Unit, 

    also benifits from the Winmen Units memory management 

    techniques, which are explained more fully in the 

    sections titled "Winmen Declared Types" and "Winmen 

    Declared Global Variables". 

       For the more technicaly minded, the paragraphs below 

    may be of interest. 

       Firstly, the WMSLIDE(); procedure does not unlink, or 

    relink, the object currently being slid, from and to the 

    3D screen map, this is left to the user to do manualy.

       The WMSLIDE(); procedure is the only routine that does 

    not call either WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); out 

    of all the routines that may need to do so.

       The WMSLIDE(); and WSELECT(); procedures are the only 

    routines that do not call WMFLOAT(); out of all the 

    routines that may need to do so.

.PA

Š        The reasons for this are as follows:-

       You may, for instance, want to slide an object in more 

    than one direction in two consecutive calls to WMSLIDE(); 

    if the WMSLIDE();procedure were to delete and add maprec's 

    and call WMFLOAT(); for you, each time it was called, we 

    would get a time lag at the start and end of each call, 

    while the object was floated and maprec's were deleted 

    from the objects old position and then added to the 

    objects new position in the 3D screen map, although this 

    lag is only very very small, it is enough to introduce a 

    jerk into what is otherwise a perfectly smooth sliding 

    action.  Dont forget we only want the object, currently 

    being slid, to be linked into the 3D screen map in its 

    final resting place.  All other maprec's belonging to that 

    object must be deleted, if they are not they will cause 

    unpredictable behavior, possibly resulting in a trashed 

    screen, or even a crash.

       On the other hand you may want to write to more than 

    one window at once, or at least, make it appear as if you 

    are. This can only be done by first selecting the window 

    to write to, using WSELECT(); then actualy writing to it. 

    If the WSELECT(); procedure had to call WMFLOAT() each 

    time it was called, this would slow things down 

    considerably and spoil our illusion, besides the windows 

    that you are writing to may all be fully visible, in 

    which case there is no need to float them to the surface 

    before writing to them.  if they are obscured and you dont 

    want to make use of the WWRITE(); or WWRITELN(); 

    procedures, to write text to a window in the background, 

    then you will have to call WMFLOAT(); either before or 

    after calling WSELECT(); and prior to writing to each 

    window. So as you can see the choice is best left up to 

    the user, for maximum flexibility.                         

.PA

Š      ------------------------------------------------------------------------

      WMMEM_STAT()                                                WMMEM_STAT()

      ------------------------------------------------------------------------


      Procedure   : Write out the current status of the heap and free list

      High Level    areas of memory or heap and free block records (depending

    on the version of Turbo Pascal being used), which are

    being managed by the Turbo Pascal heap manager routines,

    to the file assigned to the file type variable "handle".

       See below for a sample and explanation of the output

    that is generated. (usefull for debugging purposes)

       This procedure does not affect any of the window or

    menu record variables.

       This procedure is not called by any of the functions

    or procedures in the Winmen Unit.


      Syntax      : WMMEM_STAT(header,handle,r_a);


      Variables   : header : string; 

    This is a string which will be the first thing to be writen

    to the file assigned to the file variable "handle" when

    the WMMEM_STAT() procedure is called.

    The maximum string length is 255 characters, if the string

    exceeds this length, a range check error will occure.

    For your convienience there is a Winmen predefined string

    variable for this purpose, called 'comment', this is the

    string that the Winmen unit uses each time it writes to

    the Memory.Log file using the predefined file variable 

    'log', see below.


    handle : file;

    This is a file type variable, which firstly needs to be

    assigned to a particular filename, using the assign()

    procedure, if "handle" is not first assigned or a dos 

    file error occures, the programme will abort with an error

    message (see appendix for list).

    The units predefined file variable "log" may also be used,

    there is no need to assign this variable as this is done

    automatically when the windows and menus unit is called up

    in a uses clause. The file that "log" is assigned to is

    called "Memory.Log".  If the predefined file variable "log"

    is used then output goes to the "Memory.Log" file, to which

    all the units memory information goes each time the unit is

    called up from a uses clause and if any memory allocation

    errors occure during the running of the programme, if you 

    do it this way all the information is kept in one place,

    otherwise it is split between the "Memory.Log" file and

    your own file.

.PA

Š     r_a : char;

    This character defines weather the output file is to be

    created/truncated or appended to, it can only have one of

    four values:- 'R','r','A' or 'a', if any other value is

    sent the programme will abort with an error message (see

    apendix for list). If 'R' or 'r' is sent the filename 

    assigned to "handle" will be created, or if it already

    exists as a file it will be truncated. If 'A' or 'a' is 

    sent the file assigned to "handle" will be appended to,

    or created if it does not yet exist.

.PA

Š      Example     : program MEM_STAT;

 

    uses dos,crt,winmen;

  

    var

      ID,l,t,r,b : byte;             {*WINDOW PARAMETERS*}

      wind : array[1..50]of byte;    {*ARRAY TO HOLD IDs*}

      num : shortint;                {*ARRAY INDEX*}


    begin

       textbackground(0);

       clrscr;

       num := 0;

     {*WHILE A KEY NO PRESS*}

       while not(keypressed)and(num < 50)  do

       begin

  l := 90; t := 90; r := 90; b := 90;

  while(r-l < 3)or(l = 0) do {*MIN WINDOW WIDTH*}

  begin

     l := random(80);

     r := random(80);

  end;

  while(b-t < 3)or(t = 0) do {*MIN WINDOW HEIGHT*}

  begin

     t := random(25);

     b := random(25);

  end;

  ID := NEW_WIN(l,t,r,b,1,1,14,7,0);

  inc(num);                  {*CREATE THE WINDOW*}

  wind[num] := ID;           {*INCREMENT INDEX*}

  gotoxy(1,1);               {*SAVE ID TO ARRAY*}

  textbackground(7);

  clreol;

  write(scr,'Window ID=',wind[num],' l=',l,' t=',t,

    ' r=',r,' b=',b,' ',r-l,'x',b-t);

  WOPEN(ID);                 {*OPEN THE WINDOW*}

  WMCLOSE(ID);               {*CLOSE THE WINDOW*}

       end {while};

  

       while(num > 3) do             {*WHILE ARRAY INDEX IS*}

       begin                         {*GREATER THAN 1      *}

  dec(num,2);                {*DEC INX BY 2 TO MAKE*}

  WMDELETE(wind[num]);       {*HOLE IN HEAP AREA AND*}

       end;                          {*DELETE WINDOW        *}

  

       WMMEM_STAT('**Memory Condition At Abort**',log,'a');

       normvideo;

    end.                             {*WRITE MEMORY CONDITION*}

.PA

Š      Turbo Pascal

      Version Note: The freelist records for TP V5.X used to be grouped

    together in 8 byte records, starting at heapend and

    growing downwards into free memory, as each new record was

    added, the system variable Freeptr used to point to the

    end of the list, each record was made up of two fields,

    blk_org and blk_end, each one was a normalised pointer

    value, giving the starting and ending addresses of each

    free block in the programmes heap, a free block, or hole,

    is created in the heap each time a dynamic variable is

    disposed of using either freemem() or the dispose()

    procedures, the freelist records keep track of all these

    blocks.

       With the freelist records being in a block, on there

    own, at the top of ram, made them extremley dificult to

    overwrite.

       The freelist records for TP V6.0 are no longer grouped

    together, they are now each attached to there respective

    free blocks of ram in the programmes heap, they occupy the

    first 8 bytes of each free block. The two fields have

    also changed, they are now, next and size, both are still

    normalised pointers, the next field points to the next

    freeblock and record, and the size field gives the size of

    the free block.  The first freeblock is pointed to by the

    Freelist pointer variable, the Freeptr variable is no

    longer used.

       With this type of structure it becomes very easy in

    deed to overwrite the freelist record at the start of a

    particular block.  This could occure if, for instance,

    getmem() were called to allocate memory for part of a

    dynamic array.  If the array had 10 elements and we knew

    we were only ever going to use 5 of them, we could, to

    save space, allocate just enough memory for the 5, if we

    then, by mistake, use elements 6,7,8,9 and this would be

    quite legal, as we are still in range for the array index,

    we could in fact be overwriting the record belonging to

    another free block. This could occure if the free block

    allocated for the array was previously a hole in the

    programmes heap with a very small data area above it and

    then another hole in the heap above that, before the next

    chunk of data, the array elements 6,7,8, and 9 would

    overwrite both the small data area and the freelist record

    for that next free hole, the maxavail() function will fail

    when its search reaches the free hole that has just had

    its record overwritten, the value for the next field will

    be a load of old rubbish, sending maxavail() into outer

    space. This could also of occured by just allocating

    insufficient space for a structure in the call to

    getmem(), by mistake.

       Of course there is no excuse for poor or inaccurate

    programming, but at least the memory management system for

    TP V5.X did give us a small, but very greatfull margin to

    play with. From now on you had better make sure that

    every call to getmem() is bit perfect.

.PA

Š      For Owners

      Of Winmen

      Source Files: In case you are having trouble finding where your

    programme is stuck, due to the problem explained above, we

    have included another version of the _WMCHK_MEM();

    procedure in the WMCOMON2.PRS source file, to compile this

    version, instead of the standard one, all you need to do

    is delete the $ character from the {$DEFINE

    STANDARD_WMCHK_MEM} compiler statement and insert a $

    character in the {DEFINE SPECIAL_WMCHK_MEM} complier

    statement and recompile the Winmen Unit, due to some of

    the routines used in the above procedure, it will only

    compile with TP V6.X.

       It does its own free block checking and pointer

    chasing, in, I guess, much the same way as maxavail()

    does, only this one counts each pointer it has chased in

    the loop, if it reaches 10000, it will abort with an

    informative error message, as it's going to be very

    unlikely that any application will produce more than 10000

    holes in the heap, it's more likely that the above

    situation has occured. This gives us a gracefull exit,

    instead of having to ctrl, alt, del. Also refer to the

    description of the _WMCHK_MEM(); procedure for further

    information.

       The WMCOMON1.PFS file contains two versions of the

    WMMEM_STAT(); procedure one is for Turbo Pascal V5.X and

    the other is for Turbo Pascal V6.X, each one takes acount

    of the differences in the Turbo Pascal memory management

    system, each one will only compile succesfully with with

    its respective version of Turbo Pascal. The file is set

    so that the V6.X version compiles, to recompile with

    the V5.X version delete the $ character from the

    {$DEFINE VERSION_6} complier statement, insert a $

    character into the {DEFINE VERSION_4_5_55} compiler

    statement and recompile the Winmen Unit.


      General     : The two outputs below are from the above example

    programme after compliing with both the V5.0 and V6.0

    versions of the Turbo Pascal compiler. The differences,

    as far as the user is concerned, are minimal. Any

    differences that do exist between two common sections,

    ie. 1.4 in the V5.0 and 1.4 in the V6.0 are explained in

    the relevant sub-section in the explaination section

    below. If nothing is mentioned then there are no

    differences

.PA

Š      Sample Of Output From Above Programme Complled Using Turbo Pascal V5.0:-


 A)  ==========================================================================

 1.0 TURBO PASCAL WINDOWS & MENUS MEMORY LOG

     Memory Condition At Initialization:-

 1.1 There Are [0] Entries In The Freelist

     ****MEMORY STATUS TABLE FOLLOWS:-

 1.2 [FREE BLOCK NUMBER][ENDING ADDRESS][STARTING ADDRESS][BLOCK SIZE(BYTES)]


 1.3 There Are [0] Entries In The Freelist

     ****FREELIST RECORD BYTES TABLE FOLLOWS:-

 1.4 [LIST RECORD NUMBER] [BY1] [BY2] [BY3] [BY4] [BY5] [BY6] [BY7] [BY8]


 1.5 The Top Of The Freelist Is At Address [589824]

 1.6 The Top Of The Heap Is At Address [122592]

 1.7 The Heap Oragin Is At Address [122592]

 1.8 Maxavail=[532512] Memavail=[532512]

     ==========================================================================



 B)  ==========================================================================

 1.0 **Memory Condition At Abort**

 1.1 There Are [8] Entries In The Freelist

     ****MEMORY STATUS TABLE FOLLOWS:-

 1.2 [FREE BLOCK NUMBER][ENDING ADDRESS][STARTING ADDRESS][BLOCK SIZE(BYTES)]

       8             123996            123318              678

       7             124648            124146              502

       6             125826            125604              222

       5             126402            125940              462

       4             127374            126776              598

       3             127776            127512              264

       2             130764            130470              294

       1             131894            131312              582


 1.3 There Are [8] Entries In The Freelist

     ****FREELIST RECORD BYTES TABLE FOLLOWS:-

 1.4 [LIST RECORD NUMBER] [BY1] [BY2] [BY3] [BY4] [BY5] [BY6] [BY7] [BY8]

8            6     0    27    30    12     0    69    30

7            2     0    79    30     8     0   110    30

6            4     0   170    30     2     0   184    30

5            4     0   191    30     2     0   220    30

4            8     0   243    30    14     0    24    31

3            8     0    33    31     0     0    50    31

2            6     0   218    31    12     0   236    31

1            0     0    15    32     6     0    51    32


 1.5 The Top Of The Freelist Is At Address [655168]

 1.6 The Top Of The Heap Is At Address [161584]

 1.7 The Heap Oragin Is At Address [122592]

 1.8 Maxavail=[493328] Memavail=[509510]

     ==========================================================================

.PA

Š     Sample Of Output From Above Programme Complled Using Turbo Pascal V6.0:-


 A)  ==========================================================================

 1.0 TURBO PASCAL WINDOWS & MENUS MEMORY LOG

     Memory Condition At Initialization:-

 1.1 There Are [0] Free Blocks In The Heap.

     ****MEMORY STATUS TABLE FOLLOWS:-

 1.2 [FREE BLOCK NUMBER][ENDING ADDRESS][STARTING ADDRESS][BLOCK SIZE(BYTES)]


 1.3 There Are [0] Free Blocks In The Heap.

     ****FREELIST RECORD BYTES TABLE FOLLOWS:-

 1.4                        POINTER TO NEXT BLOCK   SIZE OF THIS BLOCK

     [BLOCK RECORD NUMBER] [BY1] [BY2] [BY3] [BY4] [BY5] [BY6] [BY7] [BY8]


 1.9 The First Free Block Record Is At Address [133136]

 2.0 The End Of The Heap Is At Address [655360]

 1.6 The Top Of The Heap Is At Address [133136]

 1.7 The Heap Oragin Is At Address [133136]

 1.8 Maxavail=[522224] Memavail=[522224]

     ==========================================================================



 B)  ==========================================================================

 1.0 **Memory Condition At Abort**

 1.1 There Are [8] Free Blocks In The Heap.

     ****MEMORY STATUS TABLE FOLLOWS:-

 1.2 [FREE BLOCK NUMBER][ENDING ADDRESS][STARTING ADDRESS][BLOCK SIZE(BYTES)]

       1             134552            133872              680

       2             135208            134704              504

       3             136392            136168              224

       4             136976            136512              464

       5             137952            137352              600

       6             138368            138096              272

       7             141360            141064              296

       8             142496            141912              584


 1.3 There Are [8] Free Blocks In The Heap.

     ****FREELIST RECORD BYTES TABLE FOLLOWS:-

 1.4                        POINTER TO NEXT BLOCK   SIZE OF THIS BLOCK

     [BLOCK RECORD NUMBER] [BY1] [BY2] [BY3] [BY4] [BY5] [BY6] [BY7] [BY8]

1            8     0   226    32     8     0    42     0

2            0     0    62    33     8     0    31     0

3            8     0    83    33     0     0    14     0

4            0     0   136    33     0     0    29     0

5            8     0   182    33     8     0    37     0

6            0     0   112    34     0     0    17     0

7            0     0   165    34     8     0    18     0

8            8     0    61    35     8     0    36     0


 1.9 The First Free Block Record Is At Address [133864]

 2.0 The End Of The Heap Is At Address [655360]

 1.6 The Top Of The Heap Is At Address [172328]

 1.7 The Heap Oragin Is At Address [133136]

 1.8 Maxavail=[483032] Memavail=[499320]

     ==========================================================================

Š      Explanation : A)  Section 'A' will always be present in the "Memory.Log"

file and should always have zero entries in the free

list, although the actual memory address values may

differ from above. Of course in you chose to use your

own output file, instead of the predefined handle log

then this section along with any runtime memory alloc

errors will not appear in your file, but will be in

the "Memory.Log" file. If you happen to call your own

file "Memory.Log" then the default file will be

overwritten. See below for an explanation of each

subsection, as they are the same for each output.


    B)  Section 'B' is written out each time the user calls the

WMMEM_STAT() procedure and will appear after section A

unless as mentioned in sect A) above you have defined

your own output file, in which case the file will only

contain a section 'B' for each call of WMMEM_STAT().

Below is an explanation of each part of the output:-


    1.0 This is the "comment" string sent in the WMMEM_STAT()

procedure call.


    1.1 For TP V5.X this tells you how many entries there are

in the free list.

   For TP V6.X this tells you how many free blocks

there are in the programmes heap.

   Effectively, for all TP versions this tells you how

many vacant holes there are in memory between the heap

oragin and the heap pointer, (The programmes heap goes

from HeapOrg to HeapPtr) due to some dynamic variable

or record structure having been deleted and returned

to the programmes heap by a call to either dispose()

or freemem(), or as is the case with this unit a call

to WMDELETE(). The area of ram above the heap pointer

and up to HeapEnd is called free memory, and may or

may not be owned soley by the current programme, this

is always a contigious block of ram.

   The heap is an area of ram above a programme which

has already been allocated by that programme, for all

of its dynamic variables, this includes variables

created using new(), getmem() and any procedures or

functions local variables, as and when they are

called, or in the case of this unit any new windows or

menus that have been created using NEW_WIN();

NEW_MENU(); or WMSAVE_SCR(); The heap grows upwards as

more dynamic variables are created, these holes

appear, in the programmes heap, when non-contigous

dynamic variables are deleted and returned to the

programmes heap.

   The amount of heap memory available to a programme

is controled by the {$M} compiler directive, or if

none is specified then that programme owns all

.PA

Š available ram above its code, right up to the top of

dos memory, ie. From HeapOrg to HeapEnd. The

programmes heap will grow up towards the top of its

free memory (HeapEnd) as dynamic variables are

created. The programmes stack size is also controled

by the same directive, see the Turbo Pascal reference

guide for more detailed information.

   For TP V5.X, in the area of memory above the

programmes heap, which is called free memory, you will

find the actual freelist, this contains the records

which give the starting and ending addresses of each

free block of memory (hole) in the programmes heap

area. The freelist is set up like a stack, and grows

downwards from HeapEnd, as a block of ram becomes

available, as describe above, a record which describes

its position and size is pushed onto the freelist.

   For TP V6.X there is no special area, in free

memory set asside for a freelist, instead each free

block in the programmes heap has its own record, this

record takes up the first eight bytes of each free

block, it contains two fields, the first is a pointer

to the next free block in the programmes heap and the

second gives the actual size of the current free

block. The Freeptr variable, which, in TP V5.X used

to point to the top of the freelist stack no longer

exists, this is replaced by the Freelist variable in

TP V6.X and points to the first free block in the

programmes heap.

   See the Turbo Pascal V5.X Reference Guide, P197 or

the Turbo Pascal V6.X Programmers Guide P215 for more

detailed information.


    1.2 This is the actual table of available free blocks of

ram in the programmes heap, taken from the TP V5.X

freelist or the TP V6.X free block records and gives

the block number, its ending address, starting address

and the block size, all values and addresses are in

decimal, rather than being in segment:offset format as

this makes more sense to look at. There are thoes of

course that will want segment:offset format, please

refer to sub-sect 1.4.


    1.3 See sub-section 1.1.

.PA

Š





                         PAGE 180 TO BE PRINTED HERE






.PA

Š





                         PAGE 181 TO BE PRINTED HERE






.PA 

Š    The memavail value is the sum of all free blocks in

that programmes heap plus any free memory that has

been allocated to it above HeapPtr.

   Both maxavail and memavail will depend on how the

{$M} complier directive has been set, see the Turbo

Pascal V5.X reference guide or the Turbo Pascal V6.X

Programmers Guide for more information.


    1.9 This sub-section applies only to TP V6.X

This is the address of the first free block in the

programmes heap area and is pointed to by the FreeList

variable, if this value is the same as HeapPtr then

there are no free blocks available in the programmes

heap area, see the Turbo Pascal V6.X Programmers

Guide for more information.


    2.0 This sub-section applies only to TP V6.X

This is the address at the end or extent of the free

memory that has been allocated to that programme.

This is the memory area above the programmes heap,

which is pointed to by HeapPtr. The amount of free

memory allocated to a programme will depend on how

the {$M} compiler directive has been set, see the

Turbo Pascal V6.X Programmers Guide for more

information.


      Rules Notes

      Tips & Traps: You will probably only find this procedure to be of any

    real value in a debugging situation.

       For more information on sub-sections 1.6, 1.7, 1.8, 1.9

    and 2.0 see the Turbo Pascal reference guide.

       The example creates up to 50 windows then deletes every

    third one, each deleted window becomes a vacant hole in

    the programmes heap area, its these holes that are listed

    in the freelist, for TP V5.X or at the start of each free

    block for TP V6.X, if two adjacent windows (adjacent in

    terms of memory) were to be deleted we would only create

    one hole, as the two memory areas become contigous, the

    heap manager takes care of this for us, if the lastmost

    window were to be deleted (the one occupying the memory

    area at the top of the heap) then an entry would not

    appear in the freelist for TP V5.X and there would be no

    free block record at the start of this memory area for TP

    V6.X, for this vacant memory area, as the heap manager

    will simply move the HeapPtr down, by the size of that

    block, effectively returning that area of memory to the

    free memory area above that programmes HeapPtr, for use by

    something else. The demo can be stoped before 50 windows

    is reached (69) by pressing the space bar.

.PA

Š      ------------------------------------------------------------------------

      WMMOVE()                                                        WMMOVE()

      ------------------------------------------------------------------------


      Procedure   : This procedure will move any window, menu or user screen

      High Level    (ID < 20), weather it is open or closed, from its current

    position to the new position specified in the supplied l,t

    values, if it was closed before the move it will be closed

    after the move and if open it will remain open.

       Any open object is firstly floated to the surface, so

    that it is wholy visible on the screen, the move is then

    carried out, this enables us to move objects that are

    partialy or even fully obscured by other objects, whilst

    leaving that area of screen visually correct after the

    move, this operation is so fast that the user may not

    even notice it being carried out.

       What you see on the screen is exactly what is moved,

    when the WMMOVE(); procedure is used, this includes the

    contents of windows and user screens and any titles that

    an object may have.

       After a move the objects ID_SC[] background screen

    array is always updated with the new background image from

    the area it is copied onto, this is true for windows,

    menus and user screens.

    The following conditions are errors:-

    If the IDB does not yet exist.

    If the new position will put any part of the window, menu

    or user screen off the screen.

       All the above conditions will result in the programme

    halting with an error message (see appendix for list).

       If the object moved is a window or user screen and it

    was open before the move, then it will be made the

    active one after the move, regardless of weather it was

    the active one before the move.

       The window or menus record is updated to reflect any

    changes if the operation was sucessful.

       This procedure is not called by any of the functions

    or procedures in the Winmen Unit.


      Syntax      : WMMOVE(ID,l,t);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user screen (ID < 20), as returned from NEW_MENU(); or

    NEW_WIN(); or sent to WMSAVE_SCR() if its a user screen.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).


    l : byte (B1_80);

    The new leftmost edge of the object including border, must

    be a value between 1-80 or a range check error will

    occure.

.PA

Š     t : byte (B1_25);

    The new topmost edge of the window including border, must

    be a value between 1-25 or a range check error will

    occure.


      Example     : program WM_MOVE;


    var

       m1,m1c,l,t : byte;            {*DEFINE GLOBALS*}

       mt : pt_mtext;


    begin

       getmem(mt,4*81);              {*DEFINE MENU*}

       mt^[1] := '8) Move Up';

       mt^[2] := '4) Move Left';

       mt^[3] := '6) Move Right';

       mt^[4] := '2) Move Down';

       m1 := NEW_MENU(1,4,14,7,0,15,mt,4);

       freemem(mt,4*81);


       l := 32;                      {*INIT VARBS*}

       t := 9;

       m1c := 10;

       WMTITLE(m1,1,15,'MOVE ME');   {*DO TITLE STRING*}


       while not(m1c in[0]) do       {*WHILE NOT ESCAPE*}

       begin

  m1c := POP_MENU(m1,l,t);

  case m1c of

     1 : if(t > 2) then      {*MOVE MENU UP 1 ROW*}

begin

    dec(t,2);

    WMMOVE(m1,l,t);

end;

     2 : if(l > 4) then      {*MOVE MENU LEFT 1 COL*}

begin

    dec(l,4);

    WMMOVE(m1,l,t);

end;

     3 : if(ID_WM[m1]^.r+4 < 80) then

begin               {*MOVE MENU RIGHT 1 COL*}

    inc(l,4);

    WMMOVE(m1,l,t);

end;

     4 : if(ID_WM[m1]^.b+2 < 25) then

begin               {*MOVE MENU DOWN 1 ROW*}

    inc(t,2);

    WMMOVE(m1,l,t);

end;

  end {case};

       end {while};

       normvideo;

    end {WM_MOVE}.

.PA

Š      Rules Notes  

      Tips & Traps: The Winmen Units 3D screen map system is fundimental to

    the correct operation of this procedure, the object must

    be fully linked into the 3D screen map to enable this

    procedure to keep the screen display visually correct

    each time an object is moved, under normal circumstances

    the user need not be concerned with this, but if for

    some reason this particular object has had its "maprecs"

    deleted from the 3D screen map system, perhaps using the

    WMDEL_MREC_ALL(); procedure, then the user must make

    sure that the object is re-linked into the 3D screen map

    system by using the WMADD_MREC_ALL(); procedure prior to

    the WMMOVE(); procedure being called, if this is not

    done then the 3D screen map system will not be able to

    maintain the integrity of the screen and it will become

    visually corrupt.

       The 3D screen map system will automaticaly update the

    ID_SC[] background screen arrays of any objects that were

    partialy or fully obscuring the object being moved, so

    that if they are moved, slid, floated, removed or closed

    the screen display will always be visually correct. They

    are updated with the image data that was in the ID_SC[]

    background screen array of the object being moved.

       The 3D screen map also updates its self, when the

    WMMOVE(); procedure is called, by deleting all the moved

    objects "maprecs" from the 3D screen map at its old

    position and creating new ones in its new position.

       For more detailed information on the 3D screen map

    system and it associated "types" and "variables" refer

    to the sections "Winmen Declared Types" and "Winmen

    Declared Global Variables", in particular the "maprec"

    subsection.

.PA

Š      ------------------------------------------------------------------------

      WMREMOVE()                                                    WMREMOVE()

      ------------------------------------------------------------------------ 


      Procedure   : This procedure will remove the object specified by ID 

      High Level    from the display, regardless of what other objects there 

    may be, either partially or completely covering it.

       Unlike the WMCLOSE(); procedure, which firstly floats 

    the object specified by ID to the surface, prior to 

    closing it, WMREMOVE(); appears to remove only the parts 

    of the object that are visible to the user.

       Any part of the ID object, that is covered by any other 

    object, will have its image removed from the background 

    screen array of all objects that are immediatly above it.  

    The screen arrays, of the affected objects, will then be 

    updated with the appropriate data from the background 

    screen array of the ID object, so that if the affected 

    objects are moved, slid, closed, or themselves removed 

    from view, the display will always remain visualy correct.

       As you can see there is a lot of complex array juggling 

    to be done by this procedure, however users need not 

    concern themselves with any of this, if they do not want 

    to, the WMREMOVE(); procedure takes care of everything, 

    extremely quickly and efficiently.

       If no "maprec" exists for the object at the "map_inx" 

    position corresponding to the top left hand corner of the 

    object on the screen, then no action is taken and the 

    procedure exits, it will not be removed from the display.  

    For more information on the "maprec" type refer to the 

    section "Winmen Declared Types". For more information on 

    the "map_inx" 3D screen map array index, refer to the 

    _WMADD_MREC(); and _WMDEL_MREC(); procedure definitions 

    and the MAP[map_inx] global variable, in the section 

    "Winmen Declared Variables".

       If the object specified by ID is closed or has already 

    been removed from the display, no action is taken and the 

    procedure will exit and take no action.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       The objects wmrec field ".op_cl" is updated by this 

    procedure, by setting it to "false" (closed). 

       This procedure is not called by any of the functions 

    or procedures in the Winmen Unit. 


      Syntax      : WMREMOVE(ID);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the programme will abort 

    with an error message (see appendix for list).             

.PA

Š      Example     : program REMOVE;


    uses dos,crt,winmen;


    var

       w1,w2,w3,w4,w5,w6,win,n : byte;


    begin

       textbackground(0);

       clrscr;                        {*DEFINE WINDOWS*}

       w1 := NEW_WIN(1,8,25,14,1,7,0,2,3);

       w2 := NEW_WIN(40,4,70,10,4,1,14,3,14);

       w3 := NEW_WIN(10,6,48,17,2,2,3,1,9);

       w4 := NEW_WIN(28,14,65,23,3,4,6,2,11);

       w5 := NEW_WIN(1,16,40,25,1,0,15,0,13);

       w6 := NEW_WIN(15,15,68,18,2,4,1,5,1);


       for n := 1 to 3 do             {*OPEN AND REMOVE*}

       begin

  for win := w1 to w6 do

     WOPEN(win);

  for win := w1 to w6 do

  begin

     delay(1000);

     WMREMOVE(win);

  end;

       end;


       for win := w1 to w6 do         {*OPEN LAST TIME*}

  WOPEN(win);


       for win := w1 to w6 do         {*DELETE STRUCTURES*}

       begin

  delay(1000);

  WMDELETE(win);

       end;

    end.

.PA

Š      Rules Notes

      Tips & Traps: The above example has been slowed down, with delays, so 

    that you can see exactly what is happening. The windows 

    are opened and then removed, starting with the first one, 

    to finish the windows are closed, which calls the 

    WMFLOAT(); procedure, this is so that you can see the 

    difference between the WMREMOVE(); and WMCLOSE(); 

    procedures.     

       The method that the WMCLOSE(); procedure uses to take

    an object from the display, depends on the setting of the

    system variable "WMCLOSE_WITH_REMOVE". If it is set to

    "FALSE", the default, then WMCLOSE(); will continue to use

    the WMFLOAT(); and WMREST_SCR(); procedures to close

    objects. If it is set to "TRUE" then WMCLOSE(); will use

    WMREMOVE(); to close objects. Please refer to the

    WMCLOSE(); procedure and the section "Winmen Declared

    Types, for more information.

.PA

Š      ------------------------------------------------------------------------

      WMREST_SCR()                                                WMREST_SCR()

      ------------------------------------------------------------------------

 

      Procedure   : Restore the screen data, previously saved in calls to

      High Level/   WMSAVE_SCR(), to the screen at the position specified by

      Low Level     the parameters l,t,r,b.

       The calls to WMSAVE_SCR(); may have been made by any

    one of the following Winmen routines WOPEN(); BAR_MENU();

    LIST_MENU(); or POP_MENU(); or by a users call to

    WMSAVE_SCR(); if the ID was in the range 0-19 (User saved

    screen area).

       The object and ID must have previously been created

    using either NEW_WIN(); NEW_MENU(); or WMSAVE_SCR(), if it

    is a user screen (ID < 20).

       The screen data is restored from the objects ID_SC[]

    background "screen" array, so whatever is in it at the

    time WMREST_SCR(); is caled will be used to display on the

    screen at the specified l,t,r,b area.

       Areas of screen saved during calls to the three menu

    routines and the window open routine may also be restored

    at any desired position, but bear in mind the fact that

    the objects record variables l,t,r,b will not be altered,

    so this will not actualy move the object, it will mearly

    restore a copy of what is in that objects ID_SC[]

    background "screen" array, the image under the object,

    unless this has for some reason been changed or replaced,

    to the screen at the specified position, if you want to

    move an object please refer to the WMMOVE() procedure.

       This procedure may also be called by the WMCLOSE()

    procedure, depending on how the following system switch

    is set:-


       CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface and then

       restoring the objects ID_SC[] background screen array,

       with WMREST_SCR(); to effectively remove them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does and does not call WMREST_SCR();

       CLOSE_WITH_REMOVE := false; Default.


       Please refer to the WMCLOSE(); procedure and the

    section "Winmen Declared Types" for more information.

       The objects "wmrec" is not affected in any way by this

    procedure.


      Syntax      : WMREST_SCR(ID,l,t,r,b);

.PA

Š      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a 

    user saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).


    l : (byte) B1_80;

    Leftmost edge of the area to restore to, must be a

    value between 1-80 or a range check error will occure.


    t : byte; (B1_25)

    Topmost edge of the area to restore to, must be a

    value between 1-25 or a range check error will occure.   


    r : byte; (B1_80)

    Rightmost edge of the area to restore to, must be a

    value between 1-80 or a range check error will occure.


    b : byte; (B1_25)

    Bottommost edge of the area to restore to, must be a

    value between 1-25 or a range check error will occure.


      Example     : program REST_SCR;


    uses dos,crt,winmen;


    var

       m1,l,t : byte;                {*DEFINE VARIABLES*}

       choice : word;

       mt : pt_mtext;


    begin {main}

       textbackground(0);

       textcolor(7);

       clrscr;                       {*SET UP USER TEXT AREA*}


       gotoxy(1,12);                 {*SET UP TEXT UNDER MENU*}

       textcolor(14);

       textbackground(4);

       writeln(scr,'This area of text         ');

       writeln(scr,'was under the menu        ');

       writeln(scr,'and will be copied        ');

       writeln(scr,'using WMREST_SCR()        ');

       writeln(scr,'without affecting the     ');

       writeln(scr,'menu position             ');

       delay(1500);

.PA

Š        getmem(mt,4*81);              {*DEFINE MENU*}

       mt^[1] := 'Copy Area Under The Menu';

       mt^[2] := '';

       mt^[3] := '';

       mt^[4] := '';

       m1 := NEW_MENU(1,1,2,3,4,15,mt,4);

       freemem(mt,4*81);


       choice := 10;

       while not(choice in[0]) do    {*WHILE NOT ESCAPE*}

       begin                         {*DISPLAY MENU*}

  choice := POP_MENU(m1,1,12);

  case choice of

     1 : begin

    l := 80; t := 25;{*COPY AREA UNDER MENU*}

    while(l+25 > 80)or(l < 27) do

       l := random(80);

    while(t+5 > 25)or(t < 1) do

       t := random(25);

    WMREST_SCR(m1,l,t,l+25,t+5);

end;

  end {case};

       end {while};

       normvideo;

       delay(1500);

    end {main}.


      Rules Notes

      Tips & Traps: The above example puts an area of text on the screen,

    which will just be copied around using the WMREST_SCR()

    procedure, the initial area of text will be covered up by

    a menu.

       Any saved screen area that is under (obscured) by any

    other object(s) will just be copied (restored) to the new

    specified position, having no effect at all on the

    obscuring object(s).

       The procedure also checks to see that the new area that

    is specified by the user is less than or equal to, but not

    greater than the existing area covered, although the hight

    and length may of course differ (area = h*l).  This is to

    ensure that only valid data is displayed and that the end

    of the screen array is not exceeded.  If this condition

    occures the programme will abort with an error message.

       This procedure is not influenced by, and has no affect

    at all on, the Winmen 3D screen map system.  For more

    information on the Winmen 3D screen map system and its

    associated type and variables refer to the sections

    "Winmen Declared Types" and "Winmen Declared Global

    Variables", in particular the sub-section on "maprecs".

.PA

Š      ------------------------------------------------------------------------

      WMSAVE_SCR()                                                WMSAVE_SCR()

      ------------------------------------------------------------------------


      Procedure   : Save the screen area bounded by the supplied values l,t,r

      Low Level/    b into an ID_SC[] background "screen" array, which was

      High Level    dynamically allocated to the window or menu ID in question

    when it was created using either NEW_WIN(); or NEW_MENU();

       If the ID is less than 20 its a USER saved screen area,

    in which case a new "wmrec" record is allocated along with

    an appropriatly sized ID_SC[] background "screen" array.

    If the USER saved screen is one that already exists

    through a call to WMSAVE_SCR(0-19) then no new "wmrec"

    record is allocated, but the ID_SC[] background "screen"

    array is deleted and re-allocated (see notes below for

    more detail).

       If the USER saved screen is one that exists and it is

    open it will firstly be closed with WMCLOSE(); How it is

    closed will depend on the setting of the following

    system switch:-


       CLOSE_WITH_REMOVE := false; All objects will be closed

       by firstly floating them to the surface and then

       restoring the objects ID_SC[] background screen array,

       to effectively remove them.

       CLOSE_WITH_REMOVE := true; All objects will be closed

       by using the WMREMOVE(); procedure, this makes it

       appear as if the object is being removed from the back

       of the screen, instead of from the front, as the other

       method does.

       CLOSE_WITH_REMOVE := false; Default.


       Please refer to the WMCLOSE(); procedure and the

    section "Winmen Declared Types" for more information.

       So unless you want to create a USER saved screen area

    (ID=0-19), you need not concern your self with this

    procedure. Unless for some reason you want to change the

    screen area data that is kept in an objects ID_SC[]

    background "screen" array, which is a copy of the screen

    image from under a window or menu before it was

    displayed. Dont forget the data in the objects ID_SC[]

    background "screen" array is the data that will be

    replaced on the screen at the l,t,r,b area when an object

    is closed or removed fron the display.

       Checking is done to see if the USER is trying to access

    a "wmrec" record structure ID above 19, if this occures

    then further checks are carried out to make sure that the

    new requested screen area to be saved, into the window or

    menus ID_SC[] background "screen" array, is less than or

    equal to the area that already exists for that window or

    menu, it is an error for the new area to be larger than

    the existing one (see below).

.PA

Š        This procedure is also called automatically by

    POP_MENU() LIST_MENU(), BAR_MENU() and the WOPEN()

    procedures, prior to the object being placed on the

    screen.

       The objects ID must have been previously created using

    NEW_WIN() or NEW_MENU().

       The objects "wmrec" is updated to reflect any changes.


      Winmen 3D   :    This procedure also links the object into the Winmen 3D

      Screen Map    screen map system, this is the units main routine for

    carrying out this function, it does so by making a call to

    WMADD_MREC_ALL(); so any other function or procedure that

    calls WMSAVE_SCR(); with an object ID will automatically

    have the object linked into the 3D screen map system ie.

    POP_MENU(); LIST_MENU(); BAR_MENU(): and WOPEN()

       The Winmen 3D screen map system allows objects, that

    are open on the screen (closed objects are not linked), to

    be treated is special ways, for example, objects that are

    obscured, either partially, or fully by other objects can

    be floated to the surface, removed from the back of the

    display, or closed, windows that are obscured may be

    written to, any obscured object can be moved or slid, all

    these operations can be carried out using the normal

    WMFLOAT(); WMCLOSE(); WMMOVE(); WMSLIDE(); WMREMOVE();

    WMDELETE(); WOPEN(); and WSELECT(); procedures without the

    user having to worry about the screen becoming corrupt,

    the Winmen 3D screen map system makes sure that the

    screen display is always visualy correct, no mater what

    you throw at it.

       Any obscuring object that is affected by the action of

    manipulating the obscured object, will automatically have

    its ID_SC[] background "screen" array updated with the

    correct new background image data from the object that was

    being manipulated, for example, if an obscured object is

    floated to the surface, the obscuring objects ID_SC[]

    background "screen" array will be updated to reflect the

    changing background underneath it, the object being

    manipulated will also have its ID_SC[] background "screen"

    array updated with the new screen image that it now

    covers.

       The Winmen 3D screen map system also updates its self

    automatically with the new positions of any open objects

    that have been manipulated, using any of the above

    routines.

       WMSAVE_SCR(); will only link objects into the Winmen 3D

    screen map system under the following conditions:-

       1) The ID specified is for a new user saved screen

  ID<20.

       2) The ID specified is for an existing user saved

  screen ID<20.

       3) The ID specified is for a new window, this must have

  been a call from WOPEN(); ID>19.

.PA

Š      WMSAVE_SCR(); knows if it is a call from WOPEN();

  because WOPEN(); sets the ID^.op_cl flag to "true"

  just before it calls WMSAVE_SCR(); ID^.typ is set

  to "W" and the call it makes to _WMCHK_FOR_MREC();

  will return "false" as no "maprecs" will exist for

  any object that has not yet been created.

     If the ID specified is for an existing window

  that is open then the call to _WMCHK_FOR_MREC();

  will return "true", as all open objects are linked

  into the 3D screen map, no new "maprecs" will be

  created for this ID as we do not want to double up.

     If the ID specified is for an existing window

  that is closed ID^.op_cl is set to "false" then the

  programme will abort with an error message, as this

  is an invalid operation, the ID_SC[] background

  "screen" array for that ID would be overwritten

  the next time WOPEN(); was called.


       4) The ID specified is for a new menu, this must have

  been a call from either POP_MENU(); LIST_MENU(); or

  BAR_MENU(); ID>19.

     WMSAVE_SCR(); knows if it is a call from any of

  the above three menu functions because WOPEN(); sets

  the ID^.op_cl flag to "true" just before it calls

  WMSAVE_SCR(); ID^.typ is set to "M" and the call it

  makes to _WMCHK_FOR_MREC(); will return "false" as

  no "maprecs" will exist for any object that has not

  yet been created.

     If the ID specified is for an existing menu that

  is open then the call to _WMCHK_FOR_MREC(); will

  return "true", as all open objects are linked into

  the 3D screen map, no new "maprecs" will be created

  for this ID as we do not want to double up.

     If the ID specified is for an existing menu that

  is closed ID^.op_cl is set to "false" then the

  programme will abort with an error message, as this

  is an invalid operation, the ID_SC[] background

  "screen" array for that ID would be overwritten the

  next time any of the three menu functions were

  called.

       The only other possible condition is if the ID value is

    greater than 19 (ID is for a window or a menu) and it does

    not yet exist the programme will abort with an error

    message (see appendix for list).

       For more detailed information on the Winmen 3D screen

    map system and its associated data types and variables

    plese refer to the "maprec" sub-section in the "Winmen

    Declared types" section.


      Syntax      : WMSAVE_SCR(ID,l,t,r,b);

.PA

Š      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from the NEW_MENU() or

    NEW_WIN() functions, or if it is to be a USER saved

    screen area a value between 0-19, as stated above this

    procedure is called automatically from WOPEN(), POP_MENU(),

    LIST_MENU() and BAR_MENU() so the user need not concern

    him or her self with any actual values for the ID other

    than those for a USER saved screen area (0-19), as the ID

    for a window or menu will normally be contained in the

    byte variable returned from NEW_WIN() or NEW_MENU().

       If the ID value is greater than 19 (ID is for a window

    or a menu) and it does not yet exist the programme will

    abort with an error message (see appendix for list).


    l : byte (B1_80)

    Leftmost edge of the area to save, must be a value between

    1-80 or a range check error will occure.


    t : byte; (B1_25)

    Topmost edge of the arae to save, must be a value between

    1-25 or a range check error will occure.


    r : byte; (B1_80)

    Rightmost edge of the area to save, must be a value

    between 1-80 or a range check error will occure.


    b : byte; (B1_25)

    Bottommost edge of the area to save, must be a value

    between 1-25 or a range check error will occure.


      Example     : Below is an example programme.

program SAVE_SCR;


{***********}

{*UNIT USED*}

{***********}

uses dos,crt,winmen;


{*************************}

{*DEFINE GLOBAL VARIABLES*}

{*************************}

var

   dist,               {*MOVE DISTANCE*}

   dirnum,             {*DIRECTION NUMBER*}

   sp,                 {*SPRITE NUMBER*}

   nsp : byte;         {*NUMBER OF SPRITES*}

   dir : char;         {*DIRECTION CHARACTER*}

.PA

Š{****************}

{*FUNCTION:HIT_L*}

{****************}

function HIT_L(sp,nsp : byte) : boolean;


var

   n,hit : byte;                           {*DEFINE LOCAL VARIABLES*}


begin

   hit := 0;                               {*COLISION FLAG*}

   for n := 1 to nsp do                    {*CHECK SP AGAINST ALL SPRITES*}

      if(n <> sp)and(hit = 0) then         {*EXCEPT ITS SELF*}

      begin                                {*CHECK TOP AND LEFT OF SP*}

if(ID_WM[sp]^.t >= ID_WM[n]^.t) then

   if(ID_WM[sp]^.t <= ID_WM[n]^.b) then

      if(ID_WM[sp]^.l > ID_WM[n]^.r) then

if(ID_WM[sp]^.l-dist <= ID_WM[n]^.r) then

    hit := 1;              {*COLLISION, SET HIT FLAG*}

if(hit = 0) then                   {*CHECK BOTTOM AND LEFT OF SP*}

   if(ID_WM[sp]^.b >= ID_WM[n]^.t) then

      if(ID_WM[sp]^.b <= ID_WM[n]^.b) then

if(ID_WM[sp]^.l > ID_WM[n]^.r) then

    if(ID_WM[sp]^.l-dist <= ID_WM[n]^.r) then

       hit := 1;           {*COLLISION, SET HIT FLAG*}

      end {if n};


   if(hit = 0) then

      HIT_L := false                       {*IF NO HITS RETURN FALSE*}

   else

      HIT_L := true;                       {*ELSE RETURN TRUE*}

end {*HIT_L*};

.PA

Š{****************}

{*FUNCTION:HIT_R*}

{****************}

function HIT_R(sp,nsp : byte) : boolean;


var

   n,hit : byte;                           {*DEFINE LOCAL VARIABLES*}


begin

   hit := 0;                               {*COLISION FLAG*}

   for n := 1 to nsp do                    {*CHECK SP AGAINST ALL SPRITES*}

      if(n <> sp)and(hit = 0) then         {*EXCEPT ITS SELF*}

      begin                                {*CHECK TOP AND RIGHT OF SP*}

if(ID_WM[sp]^.t >= ID_WM[n]^.t) then

   if(ID_WM[sp]^.t <= ID_WM[n]^.b) then

      if(ID_WM[sp]^.r < ID_WM[n]^.l) then

if(ID_WM[sp]^.r+dist >= ID_WM[n]^.l) then

    hit := 1;              {*COLLISION, SET HIT FLAG*}

if(hit = 0) then                   {*CHECK BOTTOM AND RIGHT OF SP*}

   if(ID_WM[sp]^.b >= ID_WM[n]^.t) then

      if(ID_WM[sp]^.b <= ID_WM[n]^.b) then

if(ID_WM[sp]^.r < ID_WM[n]^.l) then

    if(ID_WM[sp]^.r+dist >= ID_WM[n]^.l) then

       hit := 1;           {*COLLISION, SET HIT FLAG*}

      end {if n};


   if(hit = 0) then

      HIT_R := false                       {*IF NO HITS RETURN FALSE*}

   else

      HIT_R := true;                       {*ELSE RETURN TRUE*}

end {*HIT_R*};

.PA

Š{****************}

{*FUNCTION:HIT_U*}

{****************}

function HIT_U(sp,nsp : byte) : boolean;


var

   n,hit : byte;                           {*DEFINE LOCAL VARIABLES*}


begin

   hit := 0;                               {*COLISION FLAG*}

   for n := 1 to nsp do                    {*CHECK SP AGAINST ALL SPRITES*}

      if(n <> sp)and(hit = 0) then         {*EXCEPT ITS SELF*}

      begin                                {*CHECK LEFT AND TOP OF SP*}

if(ID_WM[sp]^.l >= ID_WM[n]^.l) then

   if(ID_WM[sp]^.l <= ID_WM[n]^.r) then

      if(ID_WM[sp]^.t > ID_WM[n]^.b) then

if(ID_WM[sp]^.t-dist <= ID_WM[n]^.b) then

    hit := 1;              {*COLLISION, SET HIT FLAG*}

if(hit = 0) then                   {*CHECK RIGHT AND TOP OF SP*}

   if(ID_WM[sp]^.r >= ID_WM[n]^.l) then

      if(ID_WM[sp]^.r <= ID_WM[n]^.r) then

if(ID_WM[sp]^.t > ID_WM[n]^.b) then

    if(ID_WM[sp]^.t-dist <= ID_WM[n]^.b) then

       hit := 1;           {*COLLISION, SET HIT FLAG*}

      end {if n};


   if(hit = 0) then

      HIT_U := false                       {*IF NO HITS RETURN FALSE*}

   else

      HIT_U := true;                       {*ELSE RETURN TRUE*}

end {*HIT_U*};

.PA

Š{****************}

{*FUNCTION:HIT_D*}

{****************}

function HIT_D(sp,nsp : byte) : boolean;


var

   n,hit : byte;                           {*DEFINE LOCAL VARIABLES*}


begin

   hit := 0;                               {*COLISION FLAG*}

   for n := 1 to nsp do                    {*CHECK SP AGAINST ALL SPRITES*}

      if(n <> sp)and(hit = 0) then         {*EXCEPT ITS SELF*}

      begin                                {*CHECK LEFT AND BOTTOM OF SP*}

if(ID_WM[sp]^.l >= ID_WM[n]^.l) then

   if(ID_WM[sp]^.l <= ID_WM[n]^.r) then

      if(ID_WM[sp]^.b < ID_WM[n]^.t) then

if(ID_WM[sp]^.b+dist >= ID_WM[n]^.t) then

    hit := 1;              {*COLLISION, SET HIT FLAG*}

if(hit = 0) then                   {*CHECK RIGHT AND BOTTOM OF SP*}

   if(ID_WM[sp]^.r >= ID_WM[n]^.l) then

      if(ID_WM[sp]^.r <= ID_WM[n]^.r) then

if(ID_WM[sp]^.b < ID_WM[n]^.t) then

    if(ID_WM[sp]^.b+dist >= ID_WM[n]^.t) then

       hit := 1;           {*COLLISION, SET HIT FLAG*}

      end {if n};


   if(hit = 0) then

      HIT_D := false                       {*IF NO HITS RETURN FALSE*}

   else

      HIT_D := true;                       {*ELSE RETURN TRUE*}

end {*HIT_D*};

.PA

Š{****************}

{*PROCEDURE:MAIN*}

{****************}

begin {*MAIN*}

   textbackground(0);

   textcolor(0);

   clrscr;

   WMSAVE_SCR(1,1,1,4,2);         {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(2,1,4,4,5);         {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(3,1,7,4,8);         {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(4,1,10,4,11);       {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(5,1,13,4,14);       {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(6,1,16,4,17);       {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(7,1,19,4,20);       {*SAVE THE SPRITE AREA*}

   WMSAVE_SCR(8,1,22,4,23);       {*SAVE THE SPRITE AREA*}


   textbackground(1);

   writeln(scr,' 1  ');           {*PUT SPRITE 1 ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,4);

   textbackground(2);

   writeln(scr,' 2  ');           {*PUT SPRITE 2 ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,7);

   textbackground(3);

   writeln(scr,' 3  ');           {*PUT SPRITE 3 ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,10);

   textbackground(4);

   writeln(scr,' 4  ');           {*PUT SPRITE 4 ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,13);

   textbackground(5);

   writeln(scr,' 5  ');           {*PUT SPRITE 5 ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,16);

   textbackground(6);

   writeln(scr,' 6  ');           {*PUT SPRITE ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,19);

   textbackground(7);

   writeln(scr,' 7  ');           {*PUT SPRITE ON SCREEN*}

   writeln(scr,'    ');


   gotoxy(1,22);

   textbackground(1);

.PA

Š   writeln(scr,' 8  ');           {*PUT SPRITE ON SCREEN*}

   writeln(scr,'    ');

   textbackground(0);


   nsp := 8;

   while not(keypressed) do       {*WHILE NO KEY PRESSED*}

   begin

      dist := 0;                  {*MOVE DISTANCE*}

      dirnum := 0;                {*DIRECTION*}

      sp := 0;                    {*SPRITE NUMBER*}


      while not(dirnum in[1,2,3,4]) do

dirnum := random(5);     {*GET VALID DIRECTION*}


      while not(sp in[1,2,3,4,5,6,7,8]) do

sp := random(9);         {*GET VALID SPRITE NUMBER*}


      case dirnum of

1 : begin                                    {*DIRECTION LEFT*}

dir := 'l';

dist := random(81);

if(dist > 0)and(ID_WM[sp]^.l-dist > 1) then

   if(HIT_L(sp,nsp) = false) then     {*IF NO HITS*}

      WMSLIDE(sp,dir,dist);           {*MOVE SPRITE*}

     end {case 1};

2 : begin                                    {*DIRECTION RIGHT*}

dir := 'r';

dist := random(81);

if(dist > 0)and(ID_WM[sp]^.r+dist < 80) then

   if(HIT_R(sp,nsp) = false) then     {*IF NO HITS*}

      WMSLIDE(sp,dir,dist);           {*MOVE SPRITE*}

     end {case 2};

3 : begin                                    {*DIRECTION UP*}

dir := 'u';

dist := random(26);

if(dist > 0)and(ID_WM[sp]^.t-dist > 1) then

   if(HIT_U(sp,nsp) = false) then     {*IF NO HIT*}

      WMSLIDE(sp,dir,dist);           {*MOVE SPRITE*}

     end {case 3};

4 : begin                                    {*DIRECTION DOWN*}

dir := 'd';

dist := random(26);

if(dist > 0)and(ID_WM[sp]^.b+dist < 25) then

   if(HIT_D(sp,nsp) = false) then     {*IF NO HITS*}

      WMSLIDE(sp,dir,dist);           {*MOVE SPRITE*}

     end {case 4};

      end {case dirnum};

   end {while};

   window(1,1,80,25);

   textcolor(7);

   clrscr;

end {*MAIN*}.

.PA

Š      Rules Notes

      Tips & Traps: The above "well over the top" example shows just what can

    be achieved using the WMSAVE_SCR() procedure, although

    obviously there are a lot more features than those

    demonstrated here, the WMSLIDE() procedure is also used.

       The programme consists of the main procedure, which

    sets up all the sprites or user saved screen areas and

    controls the flow of the programme through a while loop

    and case statement.

       The case statement decides which direction the sprite

    will move in and then calls one of the four separate

    procedures which are used to detect if the sprite will

    collide with any other sprite on the screen, if it would

    then it is not moved and the loop is executed again.

       The four separate HIT_?  procedures provide a basic

    means of collision detection, but it does assume that all

    the sprites or user saved screen areas are the same size,

    they can however be as small or large as you like, you can

    also have as many or as few as you like, but make sure

    that you adjust all the appropriate variables.  Its

    probably best if you study the example for a while.

       All the sprite movements and directions are completely

    random and they will never colide with each other.

       This procedure saves the screen area bounded by the

    supplied values l,t,r,b into an IS_SC[] background

    "screen" array, which is part of the win/men record

    structure created when NEW_WIN() or NEW_MENU() was called.

       If the supplied ID number is less than 20 then it is a

    USER WMSAVE_SCR() and checks are carried out to see if a

    "wmrec" record already exists for that ID, if one does

    then WMSAVE_SCR() has already been called at least once

    with that ID and so a new "wmrec" is not required, only

    the ID_SC[] background "screen" array is deleted and

    recreated for that ID. If a "wmrec" does not exist for

    that ID then one is created along with an IS_SC[]

    background "screen" array, the screen area is saved into

    it and the "wmrec" is filled in appropriatly.

       A user screen area when cleared using WCLRSCR() is

    cleared to the limits of l,t,r,b ie.  It is active right

    to its edges, unlike a window which is only active to

    l+1,t+1,r-1,b-1 ie.  1 char less all round, this is to

    allow for the window boarder.

       When the USER saves an area with WMSAVE_ SCR(0-19);

    information held in the "wmrec" record apart from its

    l,t,r,b bounds are the text background and foreground

    colours, tb and tf, which are taken from the TEXTATTR

    system variable at the time of saving, so whatever colours

    were active when WMSAVE_SCR(0-19); was called, will be

    used each time the USER saved screen is cleared, using

    WCLRSCR(); or written to, after selecting using WSELECT();

    The colours of a USER screen or indeed any window can be

.PA

Š     changed using WCOLOUR(); or WMATTRIBS(); the later will

    also change the colours of menus, these will all update

    the "wmrec" record, the only other USER saved screen

    "wmrec" record variable to be assigned is ID^.horc this is

    assigned thus:- ID^.horc := (TEXTATTR shl 8) + ' ';

    refer to the "wmrec" record type sub-section in the

    "Winmen Declared Types" section for information on all

    of the "wmrec" fields.

       Another subtle difference between USER saved screens

    and windows and menus, that is transparent to the user is

    as follows:-

       When a USER screen is saved using WMSAVE_SCR(); the

    procedure allocates the ID sent a record for holding the

    various parameters & attributes associated with the screen

    area, it also allocates just enough memory to hold the

    data for that area of screen and no more. The record is

    allocated just once to an ID, during that first call to

    WMSAVE_SCR(); and is used each time that ID calls

    WMSAVE_SCR(); The ID_SC[] background "screen" array, data

    area however is freed and re-allocated each time that ID

    calls WMSAVE_SCR(); this is to prevent data above that

    "screen" data area being overwriten should the user

    request a larger screen area to be saved into an existing

    IDs screen data area. This problem does not occure with

    windows & menus as they are always of a fixed size prior

    to displaying and are only changed through calls NEW_WIN()

    and NEW_MENU(), which handles the allocating of memory for

    both record & screen (see above).

.PA

Š      ------------------------------------------------------------------------

      WMSLIDE()                                                      WMSLIDE()

      ------------------------------------------------------------------------


      Procedure :   Slide the window, menu or user saved screen area (ID<20)

      High Level    whose reference is "ID", "nchars" in the direction of

    "dir".

       The window, menu or user saved screen area must have

    previously been created using NEW_WIN(); NEW_MENU(); or the

    WMSAVE_SCR(); procedure.

       The WMSLIDE(); procedure will slide any object in any

    direction required, left, right, up or down.

       All objects are slid exactly as you see them, so what

    is on the screen is exactly what is slid, this includes

    the contents of a window or user screen.

       The WMSLIDE(); procedure, for reasons of speed and

    efficiency, that will be explained later, does not have

    any dealings at all with the Winmen 3D screen map. What

    this means is that objects that are either partially or

    fully obscured, by other objects, are not automatically

    floated to the surface prior to the slide being carried

    out, neither are the objects "maprecs" deleted at its

    old position or created at the position it has been slid

    to, this is all left up to the user.

       The WMSLIDE(); procedure is the only routine that does

    not call either WMDEL_MREC_ALL(); WMADD_MREC_ALL(); or

    WMFLOAT(); out of all the routines that may need to do so.

       The reasons for this are as follows:-

       You may, for instance, want to slide an object in more

    than one direction in two consecutive calls to WMSLIDE();

    if the WMSLIDE(); procedure were to delete and add

    maprec's and call WMFLOAT(); for you, each time it was

    called, we would get a time lag at the start and end of

    each call, while the object was floated and maprec's were

    deleted from the objects old position and then added to

    the objects new position in the 3D screen map, although

    this lag is only very very small, it is enough to

    introduce a jerk into what is otherwise a perfectly smooth

    sliding action. Dont forget we only want the object,

    currently being slid, to be linked into the 3D screen map

    in its final resting place. All other maprec's belonging

    to that object must be deleted, if they are not they will

    cause unpredictable behavior, possibly resulting in a

    trashed screen, or even a crash.

       The above implication does of course mean that the user

    will have to carry out these operations for himself,

    making sure that the object to be slid is firstly brought

    to the surface using WMFLOAT(); unless it is already one

    of the topmost objects, in which case there is no need to

    call WMFLOAT(); next you will have to make a call to

.PA

Š     WMDEL_MREC_ALL(); to delete the objects "maprecs" from the

    current position, you are now free to slide the object as

    many times, and in as many directions as you wish, or just

    the once, without making further calls to either

    WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); When you have

    completely finished sliding the object, for this

    particular operation, and it is in its final resting

    place, you must now make the call to WMADD_MREC_ALL(); to

    relink the object into the Winmen 3D screen map system.

       If the above procedure is not followed, make no

    mistake, you will finish up with a corrupted display,

    especially if obscured objects are slid before firstly

    floating them to the surface. If you have missed a call

    to either WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); it may

    be a while before a problem manifests its self, but it

    will. However the WMADD_MREC_ALL(); procedure does make

    it impossible for the user to create more than one set

    of "maprecs" in the same screen position, as it will

    simply exit with no action if this is attempted.

       For more information on the Winmen 3D screen map system

    and its associated types and variables please refer to

    the "maprec" type sub-section in the "Winmen Declared

    Types" section.

       The screen background image you may expect to see

    revealed from under an object, during sliding, may be

    diferent to what you are expecting, if for some reason it

    has been changed by using the WMSAVE_SCR() procedure on

    that particular ID at some time.

       The window, menu or user saved screen "wmrec" record is

    updated to reflect any changes.

       This procedure is not called by any of the functions

    or procedures in the Winmen unit.


      Syntax      : WMSLIDE(ID,dir,nchar);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a 

    user saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).


    dir : char;

    This is the direction in which you wish to move the window

    menu or USER saved screen area and can be any of the 

    following characters:- 'l','L','r','R','u','U','d','D'.

    Any other character is ignored and no slide will take 

    place. 

.PA

Š     nchar : byte;

    This is the distance or number of characters that you wish

    to slide the window, menu or USER saved screen area. If 

    this distance will put any part of the window, menu or USER

    saved screen area off the screen, then the programme will 

    be aborted with an error message to that effect (see 

    apendix for list).


      Example 1   : program WM_SLIDE1;


    uses dos,crt,winmen;


    var

       m1,m1c,l,t : byte;            {*DEFINE GLOBALS*}

       mt : pt_mtext;

       first : boolean;


    begin

       getmem(mt,4*81);              {*DEFINE MENU*}

       mt^[1] := '8) Slide Up';

       mt^[2] := '4) Slide Left';

       mt^[3] := '6) Slide Right';

       mt^[4] := '2) Slide Down';

       m1 := NEW_MENU(1,4,14,7,0,15,mt,4);

       freemem(mt,4*81);


       l := 32;                      {*INIT VARBS*}

       t := 9;

       m1c := 10;

       WMTITLE(m1,1,15,'SLIDE ME');  {*DO TITLE STRING*}


       first := true;                {*SET FIRST FLAG TRUE*}

       while not(m1c in[0]) do       {*WHILE NOT ESCAPE*}

       begin

  m1c := POP_MENU(m1,l,t);

  case m1c of                {*IF FIRST TIME OPENED*}

  1..4 : if(first = true) then

begin

    WMFLOAT(m1);     {*FLOAT MENU TO SURFACE*}

    WMDEL_MREC_ALL(m1);{*DELETE ALL MRECS*}

    first := false;  {*SET FIRST FLAG FALSE*}

end;

  end {case}

  case m1c of

     1 : if(t > 1) then      {*MOVE MENU UP 1 ROW*}

begin

    dec(t);

    WMSLIDE(m1,'u',1);

end;

.PA

Š      2 : if(l > 2) then      {*MOVE MENU LEFT 1 COL*}

begin

    dec(l,2);

    WMSLIDE(m1,'l',2);

end;

     3 : if(ID_WM[m1]^.r+2 < 80) then

begin               {*MOVE MENU RIGHT 1 COL*}

    inc(l,2);

    WMSLIDE(m1,'r',2);

end;

     4 : if(ID_WM[m1]^.b+1 < 25) then

begin               {*MOVE MENU DOWN 1 ROW*}

    inc(t);

    WMSLIDE(m1,'d',1);

end;

  end {case};

       end {while};

       normvideo;

    end {WM_SLIDE}.


      Example 2   : program WM_SLIDE2;


    uses dos,crt,winmen;


    var

       m1,m1c,l,t : byte;            {*DEFINE GLOBALS*}

       mt : pt_mtext;


    begin

       getmem(mt,4*81);              {*DEFINE MENU*}

       mt^[1] := '8) Slide Up';

       mt^[2] := '4) Slide Left';

       mt^[3] := '6) Slide Right';

       mt^[4] := '2) Slide Down';

       m1 := NEW_MENU(1,4,14,7,0,15,mt,4);

       freemem(mt,4*81);


       l := 32;                      {*INIT VARBS*}

       t := 9;

       m1c := 10;

       WMTITLE(m1,1,15,'SLIDE ME');  {*DO TITLE STRING*}


       while not(m1c in[0]) do       {*WHILE NOT ESCAPE*}

       begin

  m1c := POP_MENU(m1,l,t);

  case m1c of

     1 : if(t > 1) then      {*MOVE MENU UP 1 ROW*}

begin

    dec(t);

    WMFLOAT(m1);

    WMDEL_MREC_ALL(m1);

    WMSLIDE(m1,'u',1);

    WMADD_MREC_ALL(m1);

end;

.PA

Š      2 : if(l > 2) then      {*MOVE MENU LEFT 1 COL*}

begin

    dec(l,2);

    WMFLOAT(m1);

    WMDEL_MREC_ALL(m1);

    WMSLIDE(m1,'l',2);

    WMADD_MREC_ALL(m1);

end;

     3 : if(ID_WM[m1]^.r+2 < 80) then

begin               {*MOVE MENU RIGHT 1 COL*}

    inc(l,2);

    WMFLOAT(m1);

    WMDEL_MREC_ALL(m1);

    WMSLIDE(m1,'r',2);

    WMADD_MREC_ALL(m1);

end;

     4 : if(ID_WM[m1]^.b+1 < 25) then

begin               {*MOVE MENU DOWN 1 ROW*}

    inc(t);

    WMFLOAT(m1);

    WMDEL_MREC_ALL(m1);

    WMSLIDE(m1,'d',1);

    WMADD_MREC_ALL(m1);

end;

  end {case};

       end {while};

       normvideo;

    end {WM_SLIDE}.


      Rules Notes

      Tips & Traps: The two above examples show quite clearly when and where

    to use the WMFLOAT(); WMDEL_MREC_ALL(); and

    WMADD_MREC_ALL(); procedures to support the WMSLIDE();

    procedure.

       Before we start make sure you have the Num Lock, on

    the keyboard set to on before you start, then you can

    use the 8,6,2 and 4 direction keys on the keypad.

       The first example shows the correct way to tackle that

    particular situation. A flag is set prior to entering the

    while loop, which is the main control loop for the

    POP_MENU(); function, as soon as a valid menu option is

    returned, requiring the menu to be slid, the first case

    statement picks this up and if the "first" flag is set

    "true", indicating this is the first time the menu has

    been used in this while loop, and the chosen option

    was 1..4 then we float the menu to the surface, not realy

    necassary here but put in for the purposes of the

    demonstration, we then delete all the menus "maprecs",

    this is necassary as the menu is about to be slid. The

    second case statement then picks up and slides the menu in

    the correct direction, the desired number of characters.

    No mater how many times we now slide the menu from within

    that while loop no more calls will need to be made to

.PA

Š     WMFLOAT(); WMDEL_MREC_ALL(); or WMADD_MREC_ALL(); as the

    "first" flag remains "false", it is not necassary, as the

    menu is never obscured by other objects and there are no

    other operations to worry about in that while loop. The

    menu and while loop both exit when the escape key is

    pressed. The "first" flag would be set back to "true" if

    the programme flow ever returned to this while loop. We

    never need to make a call to WMADD_MREC_ALL(); because,

    just as we finish using the menu, it is automatically

    closed when we press the escape key and closed objects

    never need to be linked into the Winmen 3D screen map

    system, the fact that the POP_MENU(); function will be

    calling the WMCLOSE(); procedure, which in turn calls

    WMFLOAT(); or WMREMOVE(); without there being any

    "maprecs" present in the 3D screen map, for this menu,

    will not cause any harm, as both WMFLOAT(); and

    WMREMOVE(); will exit, without taking any action, if there

    checks reveal ther are no "maprecs" for this object, and

    as the menu is already on the surface, no float is

    required anyway and a close by WMREST_SCR(); will be

    visibly, exactly the same as a close by WMREMOVE(); if the

    object is on the surface (Please refer to the WMCLOSE();

    procedure for more detail). If for example we only exited

    the menu and did not automaticaly close it, by having an

    option on the menu to do this, then we would need to make

    a call to the WMADD_MREC_ALL(); procedure to ensure the

    menu was fully linked into the 3D screen map. Tackeling

    the above situation in this way makes the sliding much

    smoother, as I am sure you will aggree, when you compare

    it to the second example.

       The second example is still correct, but is a good

    example of overkill, a real belt and braces effort, this

    shows up in the speed of sliding, if you keep any one of

    the numeric keypad 8,6,2, or 4 keys pressed, with Num

    Lock on, you will see how jerkey it is when compared

    with the first example, this is because we are calling

    WMFLOAT(); and WMDEL_MREC_ALL(); before every single

    slide and WMADD_MREC_ALL(); after every slide, this is

    totaly unnecessary as we do not intend carrying out any

    other operations in between any of the slide operations,

    that will require the Winmen 3D scren map system to be

    updated with the menus new position, if we were then we

    would indeed have to use this method.

       If we just wanted to make one slide in one direction,

    as is most often the case, then we would carry out the

    following operations:-


       code.....

       WMFLOAT(ID);

       WMDEL_MREC_ALL(ID);

       WMSLIDE(ID,dir,nchar);

       WMADD_MREC_ALL();

       code.....

.PA

Š        Or if we wanted to make more than one slide at the

    same time:-


       code.....

       WMFLOAT(ID);

       WMDEL_MREC_ALL(ID);

       WMSLIDE(ID,dir,nchar);

       WMSLIDE(ID,dir,nchar);

       WMSLIDE(ID,dir,nchar);

       WMADD_MREC_ALL();

       code.....


       So it would pay you to study the examples to enable

    you to get the most from the WMSLIDE(); procedure.

       This procedure determines the direction of sliding and

    calls all the required routines to facilitate the slide,

    it also checks that the win/menu ID is a valid one and

    that sliding it nchars will not take it off the screen,

    both of these are error conditions and cause the currently

    executing programme to terminate with an error message.

       If the chosen window exists but is not open it is

    opened for use and will be the active one after sliding.

       If the window was open but was not the active one it

    will be slid and will be the active one after sliding.

       An attempt to slide a closed menu will result in a

    termination as it cannot be opened from the slide

    routine. Open active and non active menus may be slid,

    Including POP LIST and BAR Menus.

       A user saved screen area may also be slid.

.PA

Š      ------------------------------------------------------------------------

      WMTITLE()                                                      WMTITLE()

      ------------------------------------------------------------------------


      Procedure   : Put a title string "str" into the top edge of a window, 

      High Level    menu or USER saved screen area (ID < 20), whoose reference 

    is ID, the "str" must be <= (r-l-3), to enable it to fit.

       The window, menu or USER saved screen area must have

    previously been created using NEW_WIN(), NEW_MENU() or

    WMSAVE_SCR().

       The objects border background "bb" and foreground "bf"

    colours must also be specified.

       A window or USER saved screen area should be titled

    after it is opened, whereas a menu should be titled before

    it is opened (see below).

       A window or USER saved screen may be titled when it is

    open or closed, active or non active.

       A closed window or USER screen will be opened

    automaticaly when WMTITLE() is used, thus it will become

    the active one after titling, so if you do not want it to

    become the active one, you must title it after opening.

       A menu may be titled when it is open and non-active or

    when it is closed, it cannot be titled if it is open and

    active, as you are actually inside the menu procedure, it

    becomes non-active as soon as a selection is made and

    control is passed back to the main programme, so If you

    want a title to appear on a menu as soon as it is opened

    then you must title it before it is opened, thus:-

       WMTITLE(ID,bb,bf,str);

       POP_MENU(ID,t,l);

       The earliest a menu can be titled after opening is when

    it becomes non-active ie.  after a selection has been

    made:-

       POP_MENU(ID,t,l);

       WMTITLE(ID,bb,bf,str);

       So in the later case the title would not appear on the

    menu until a selection had been made and control passed

    back to the main programmes next instruction which is

    WMTITLE().

       The WMTITLE() procedure does not normaly affect window,

    menu or USER saved screen currency, only as above.

       The procedure will halt the programme with an error

    message if an attempt is made to title a window, menu or

    USER saved screen that does not yet exist.

       This procedure does not alter any of the IDs record

    varbs, except for the ID^.op_cl flag of a window or USER

    screen, if it was closed prior to using WMTITLE(), the

    flag will of course be set to true after use.

       This procedure is not called by any of the Winmen units

    functions or procedures.


      Syntax      : WMTITLE(ID,bb,bf,str);

.PA

Š      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    USER saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    USER saved screen area.

       If the ID does not yet exist the programme will abort

    with an error message (see appendix for list).


    bb : byte; (B0_15)

    Border background colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).


    bf : byte; (B0_15)

    Border foregroung colour, must be a value in the range

    0-15 or a range check error will occure. (see colour

    table below).                                             


    str : string;

    This is the actual title string to be used, it will be

    placed, centred, in the top edge of the border, or the top

    row, if it is a USER saved screen area.

       The string must conform to the following formula:-

    "str" <= (r-l-3) where r and l are the right and lefthand

    edges of the window, menu or USER saved screen area

    respectivly, if "str" is too long the programme will abort

    with an error message (see apendix for list).

       The string will be displayed between two vertical twin

    bar characters thus:- ºTitle Stringº the string can of

    course be consatenated from any of the valid ascii type

    characters.


                                          CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink      

.PA

Š      Example     : program WM_TITLE;


    uses dos,crt,winmen;              {*DEFINE USED UNITS*}


    var                               {*DEFINE GLOBALS*}

       m1,m1c,w1 : byte;

       mt : pt_mtext;


    begin

       textbackground(0);

       textcolor(7);

       clrscr;

       getmem(mt,9*81);               {*DEFINE MENU & WINDOW*}

       mt^[1] := '1) Open Window Then Title';

       mt^[2] := '2) Title Window Then Open';

       mt^[3] := '3) Title Menu Then Open';

       mt^[4] := '4) Title An Open Menu';

       mt^[5] := '5) Clear Menu Title';

       mt^[6] := '6) Slide Window (No Effect)';

       mt^[7] := '7) Move Window (No Effect)';

       mt^[8] := '8) Slide Menu (No Effect)';

       mt^[9] := '9) Move Menu, (No Effect)';

       m1 := NEW_MENU(4,4,14,7,0,15,mt,9);

       freemem(mt,9*81);


       w1 := NEW_WIN(3,15,34,24,4,4,14,7,0);


       m1c := 10;

       while not(m1c in[0]) do        {*WHILE ESC NOT PRESSED*}

       begin

  m1c := POP_MENU(m1,3,3);

  case m1c of

     1 : begin                {*OPEN WIN THEN TITLE*}

    WOPEN(w1);

    write(scr,'Opened <RET> = Title');

    readln;

    WMTITLE(w1,1,15,'WINDOW TITLE');

    write(scr,'Titled <RET> = Re-Title');

    readln;

    WMTITLE(w1,1,15,'TITLE');

    write(scr,'Re-Titled <RET> = Menu');

    readln;

    WMCLOSE(w1);

end;

.PA

Š      2 : begin                {*TITLE WIN AUTO OPEN*}

    WMTITLE(w1,1,15,'WINDOW TITLE');

    writeln(scr,'Opened = Automatic');

    write(scr,'Titled <RET> = Re-Title');

    readln;

    WMTITLE(w1,1,15,'TITLE');

    write(scr,'Re-Titled <RET> = Menu');

    readln;

    WMCLOSE(w1);

end;

     3 : begin                {*TITLE MENU THEN OPEN*}

    WMCLOSE(m1);

    WMTITLE(m1,1,15,'MENU TITLE');

    gotoxy(3,3);

    normvideo;

    write(scr,'Titled <RET> = Menu');

    readln;

    clrscr;

end;

     4 : begin                {*OPEN MENU THEN TITLE*}

    WMTITLE(m1,1,15,'ITS A MENU TITLE');

    gotoxy(3,2);

    normvideo;

    write(scr,'Titled <RET> = Re-Title');

    readln;

    WMTITLE(m1,1,15,'TITLE');

    gotoxy(3,2);

    clreol;

    write(scr,'Re-Titled <RET> = Menu');

    readln;

    gotoxy(3,2);

    clreol;

end;

     5 : WMCLOSE(m1);         {*CLEAR MENU TITLE*}

     6 : begin

    WMTITLE(w1,1,15,'WINDOW TITLE');

    WMDEL_MREC_ALL(w1);

    WMSLIDE(w1,'r',46);

    WMSLIDE(w1,'l',46);

    WMADD_MREC_ALL(w1);

    delay(1000);      {*SLIDE WINDOW, TITLE*}

    WMCLOSE(w1);      {*WILL NOT BE LOST*}

end;

     7 : begin                {*MOVE WINDOW, TITLE*}

    WOPEN(w1);        {*WILL NOT BE LOST*}

    WMTITLE(w1,1,15,'WINDOW TITLE');

    delay(1000);      {*AS WMMOVE() DOES'NT*}

    WMMOVE(w1,49,15); {*CALL WMCLOSE(), IT*}

    delay(1000);      {*DID IN V1.0*}

    WMMOVE(w1,3,15);

    delay(1000);

    WMCLOSE(w1);

end;

.PA

Š      8 : begin                {*SLIDE MENU, TITLE*}

    WMFLOAT(m1);      {*WILL NOT BE LOST*}

    WMDEL_MREC_ALL(m1);

    WMSLIDE(m1,'r',46);

    WMSLIDE(m1,'l',46);

    WMADD_MREC_ALL(m1);

end;

     9 : begin                {*MOVE MENU, TITLE*}

    WMMOVE(m1,49,3);  {*WILL NOT BE LOST*}

    delay(1000);

    WMMOVE(m1,3,3);

end;

  end {case};

       end {while};

       normvideo;

    end {WM_TITLE}.


      Rules Notes

      Tips & Traps: If the WMTITLE() proc is used just prior to WMATTRIBS() the

    WMATTRIBS() procedure will effectively delete the title

    just issued, THIS WILL ONLY APPLY TO CLOSED MENUS, as the

    WMATTRIBS() procedure re-builds the mmenu array using the

    new supplied values, open menus will not be affected as the

    WMATTRIBS() procedure does not write to the screen, open or

    closed windows and USER saved screens will not be affected 

    as they are generated and do not have a permenant array 

    like the mmenu array for menus. 

       Closed menus that are titled and intended for opening

    as bar menus will not display a title as the border part

    of the mmenu array is not used in the _MBDISPLAY()

    procedure which displays the bar menu, as it seems

    inapropriate to give a bar menu a titling facility.

       Open bar menus that are titled will not have there title

    displayed even after a call to WMMOVE(), for the same 

    reason as above. 

       All other open or closed windows, menus and USER saved

    screens may be titled, if they are open the title will be

    displayed immediatly, menus will also have the title put

    into there ID_MM[] "mmenu" array, so that if they are

    moved with the WMMOVE() procedure the title will still

    display, we need to do this as the WMMOVE() procedure

    calls the _MDISPLAY() procedure for list and pop menus,

    which does use all of the ID_MM[] "mmenu" array, including

    the border, for bar menus see above.

       If a title already exists and it is longer than the new

    one, it will still be fully overwritten by the WMTITLE()

    procedure, both on the screen, if open, and in a menus

    ID_MM[] "mmenu" array. If the new shorter title was put

    into the menus ID_MM[] "mmenu" array, without padding it

    out to fully overwrite the old longer one and an open menu

    was retitled, with a shorter title, the screen would be

    visually correct, because we overwrite the old title

    there, but if the menu was moved with the WMMOVE()

.PA

Š     procedure both the old and new underlapping title would

    appear after the move, this is because WMMOVE() calls the

    _MDISPLAY() procedure, which uses all of the menus

    ID_MM[] "mmenu" array to display the menu, which would

    still contain part of the old longer title.

       The character used to wipe out the old title when

    WMTITLE() or WMCLOSE() are called will be in the "wmrec"

    record variable "horc" which was set up in the call to

    NEW_WIN() or NEW_MENU(). USER saved screens also use this

    character word which in there case was set up in the call

    to WMSAVE_SCR()

    and is made up thus "horc" := (TEXTATTR shl 8) + ' '; so 

    any existing title will be wiped using space characters, 

    the colours will be as per the TEXTATTR byte at the time of

    calling the WMSAVE_SCR() procedure.

       Any window, menu or USER saved screen area that has a

    title will loose the title when it is closed using the

    WMCLOSE() procedure, this is so that you can have a

    titleless window menu or USER saved screen, each time it

    is opened, of course there are thoes that will say the

    titles ought to be retained. For windows and USER saved

    screens this is not possible as they are generated each

    time they are opened, they do not have a permenant array

    like the ID_MM[] "mmenu" array for menus, and to have one

    would take up much more valuable memory space, so there is

    nowhere to put the title, menus could conceivably retain

    there titles by removing the code which deletes them from

    the WMCLOSE() procedure, the only problem then would be

    deleting a title if one were not required, we would need

    to send a string of that menus border type chars each time

    we wanted to delete a title.

       The example takes you through and demonstrates

    everything we have discussed here, it would pay you to

    study it.

.PA

Š      ------------------------------------------------------------------------

      _WMADD_MREC()                                              _WMADD_MREC()

      ------------------------------------------------------------------------

     

      Procedure   : Creat a new maprec and add it to the 3D screen map on the

      Low Level     END of the list at the specified position.

       The new record is created dynamically and the three 

    fields are filled in [IDB,sc_inx,next].

       Memory for the maprec is allocated from the heap, no 

    checks are carried out to see if there is sufficient 

    contigious memory available for the new record.  

       The "next" field of the maprec preceding the current 

    one, in the singley linked list, is filled in with the 

    pointer value (address) of the newley created record, thus 

    linking the new record to the end of the list at the 

    specified map index position (map_inx).

       If the newley created maprec is the first one in the 

    list then its pointer value (address) is put into the 3D 

    screen map array (MAP[map_inx]) at the specified index 

    (map_inx). The "next" field of the newley created record 

    is always set to nil, indicating the END of the list.

       This procedure assumes that no maprec exists for the 

    object, at the specified map_inx location.  If one does 

    then there will be two in the list at location map_inx 

    after this routine has been called, this may cause 

    unpredictable results, or even a fatal error when calling 

    any ather routine that uses the 3D screen map.  

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().  

       No checks are carried out on the validity of data 

    supplied to this low level procedure, so extra care is 

    needed.

       The objects wmrec is not affected by this procedure.        

       This procedure is called by:- WMADD_MREC_ALL();


      Syntax      : _WMADD_MREC(ID,sc_inx,map_inx);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the results will be 

    unpredictable, as the ID is not checked.                   


    sc_inx : word;

    This is the index into the objects screen array,

    (ID_SC[ID]^[sc_inx]), that corresponds to the "map_inx"

    position in the 3D screen map array. This effectively

    crossreferences and locates that objects screen array

    within the 3D screen map.

.PA

Š     map_inx : word;

    This is the 3D screen map location index, (MAP[map_inx])

    at which the newley created maprec is to be linked, at the

    END of the list, or to MAP[map_rec] if it is the first

    record. 

       The address of the new record is put into the 

    MAP[map_rec] pointer variable if it is the first record in 

    the list, or into the "next" field pointer variable of the 

    maprec on the END of the list if some already exist.


      Example     : procedure _ADDRECS(ID);


    var

       ncol,nrow : byte;

       mapinx,map_inx,sc_inx : word;

       IDWM : pt_wmrec;


    begin

       IDWM := ID_WM[IDB];            {*GET POINTER TO WMREC*}

       nrow := num rows in object     {*CALC ROWS & COLS*}

       ncol := num cols in object

       mapinx := top left char posn   {*CALC MAP ARRAY INDEX*}

       sc_inx := 0;                   {*W/M SCREEN ARRAY INX*}

       for each row in object do      {*FOR EACH ROW IN OBJ*}

       begin

  map_inx := mapinx;          {*UPDATE MAP COL INDEX*}

  for each column in row do   {*FOR EACH COL IN ROW*}

  begin                       {*ADD A RECORD TO MAP*}

     _WMADD_MREC(ID,sc_inx,map_inx);

     inc map_inx to next column{*INC MAP ROW INDEX*}

     inc sc_inx to next column{*INC OBJ SCR ARY INX*}

  end;                        {*INC TO NEXT ROW*}

  inc mapinx to start of next row

       end;

    end {_ADDRECS};


      Rules Notes

      Tips & Traps: The above example, in a mixture of Pascal and psuedo code,

    shows how to add, or link in, a complete maprec structure 

    to the 3D screen map, for any given object (window, menu 

    or user screen). 

       The example, in common with any of the Windows and 

    Menus low level routines, does not carry out any checking 

    on the parameters supplied to it by the user.  There would 

    also normaly be quite a few internal checks caried out, 

    for instance, on memory, to ensure there is going to be 

    sufficient to allocate for the new records, this would 

    usualy be done by a preceding high level type routine.

       As with any routine that uses pointers and allocates or 

    deallocates memory, as does _WMADD_MREC(); great care 

    needs to be taken and in particular checks needs to be 

    carried out prior to its use.

.PA

Š      ------------------------------------------------------------------------

      _WMBOX_ATTRIBS()                                        _WMBOX_ATTRIBS()

      ------------------------------------------------------------------------

      Procedure   : Internal procedure called by the following functions an

      Low Level     procedures:- NEW_WIN(), NEW_MENU(), EXPLODE(), WMATTRIBS()  

    to set the six record variables "tlc", "trc", "blc", "brc

    "horc" and "verc", to there correct screen ram format wor

    values, for the supplied "btype", "bb" and "bf" values

    for that particular window or menu

    These six values will be a combination of character valu

    and the textbackground and foreground colours, see belo

    for a fuller explanation

    The window or menus record is updated to reflect th

    changes

    No checks are carried out on the validity of data supplie

    to this low level procedure, so extra care is needed.


      Syntax      : _WMBOX_ATTRIBS(btype,bb,bf,tlc,trc,blc,brc,horc,verc);


      Variables   : btype : byte; (B1_4)

    Type of border required around the menu edge, must be 

    value between 1-4 or a range check error will occure

    The possible border types are as follows:

       1 = Double horizontal and double vertical bars

       2 = Single horizontal and single vertical bars

       3 = Double horizontal and single vertical bars

       4 = Single horizontal and double vertical bars


    bb : byte; (B0_15)

    Border background colour, must be a value in the rang

    0-15 or a range check error will occure. (see colou

    table below)

 

    bf : byte; (B0_15)

    Border foregroung colour, must be a value in the rang

    0-15 or a range check error will occure. (see colou

    table below).                                            

 

    var tlc : word

    Address of the word attribute variable for the top left

    corner character of the box

 

    var trc : word

    Address of the word attribute variable for the top right

    corner character of the box

 

    var blc : word

    Address of the word attribute variable for the bottom left

    corner character of the box


    var brc : word

    Address of the word attribute variable for the bottom right

    corner character of the box

.PA

Š     var horc : word

    Address of the word attribute variable for the horizontal

    characters in the box


    var verc: word

    Address of the word attribute variable for the vertical

    characters in the box.


      All the values used for the character/colour attribute word are made up

      in the following way:

      CHARACTER,COLOUR (but DOS requires the low byte first!)

      LO× BYTÅ FIRSÔ º COLOUÒ VALUE® HIGÈ BYTÅ LASÔ º ASCIÉ CHARACTER VALUE


      The colour byte is made up in the following way:

      Bit 7 : blink flag 0=off 1=on --------------[0 100 1000]

      Bit 6 : -|                                      |   | 

      Bit 5 :  -> Character background colour 0-7 ----|   | 

      Bit 4 : -|                                          | 

      Bit 3 : -|                                          | 

      Bit 2 :  -> Character foreground colour 0-15 -------|

      Bit 1 : -|

      Bit 0 : -|


      A xref of useful box type ASCII char values and a colour value chart

      follows:

  CGA                    MDA

      Colour Table: Value      Foreground     Background

    0          Black          Black          Normal Background

    1          Blue           Blue           Underline

    2          Green          Green

    3          Cyan           Cyan

    4          Red            Red

    5          Magenta        Magenta

    6          Brown          Brown

    7          White          White          Normal Foreground

    8          Grey           Black+Blink

    9          Light Blue     Blue+Blink

    10         Light Green    Green+Blink

    11         Light Cyan     Cyan+Blink

    12         Light Red      Red+Blink

    13         Light Magenta  Magenta+Blink

    14         Yellow         Brown+Blink

    15         Bright Wight   White+Blink

.PA

Š





                         PAGE 221 TO BE PRINTED HERE






.PA

Š      Rules Notes

      Tips & Traps: The above example closes and opens a window, with a new

    box type "btype", border background "bb" and foreground

    "bf" colour each time a key is pressed, the values are

    all randomly chosen, the programme is exited by pressing

    the space bar

    This procedure will only have full effect on windows a

    they are generated using the above record variables each

    time they are opened. It will have no effect on USER save

    screens as they cannot be opened and do not have a border

    It will also have no effect on menus as there border is

    not generated each time they are opened, they are displayed

    from there mmenu array and that is only built in the call

    NEW_MENU(), although if _WMBOX_ATTRIBS() is called and

    the menu is then closed using WMCLOSE(), the next time it

    is opened the top row of the border will display in the

    new "btype", "bb" and "bf" values, this is because the

    WMCLOSE() procedure wipes the top row of the border to

    erase any title there may be, it uses the record variable

    tlc,trc,blc,brc,horc and verc to do so, which are of course

    changed in the call to _WMBOX_ATTRIBS()

.PA

Š      ------------------------------------------------------------------------

      _WMCHK_EXIST()                                            _WMCHK_EXIST()

      ------------------------------------------------------------------------

      Procedure   : Internal procedure called by the following functions an

      Low Level     procedures:- WOPEN(), WSELECT(), WCLRSCR(), WCOLOUR()

    POP_MENU(), LIST_MENU(), BAR_MENU(), MPIC_COL()

    MBAR_COMMENT(), MCHANGE_CHAR(), WMSAVE_SCR(), WMREST_SCR(

    WMCLOSE(), WMSLIDE(), WMDELETE(), WMTITLE(), WMATTRIBS()

    WMMOVE()

    The procedure is called by all the functions and procedure

    that take a wmrec record structure IDB byte identifier a

    one of the parameters

    A check is made to see if the requested record structur

    exists, the complete record structure comprises of the     

    wmrec structure and the screen array, for both windows and

    menus and additionally the mmenu array and comment array

    for menus, the check is done by seeing if the pointer for

    that IDs wmrec is nil or not thus:-

    if(ID_WM[ID] = nil) then; As you can see the pointer is in

    the appropriate pointer array.

    If the pointer is nil then the record structure does not

    yet exist, has been deleted with WMDELETE(), or it has

    somehow become unlinked, effectively that window, menu or

    USER saved screen does not exist and the current programme

    will abort with an error message (see appendix for list).

    If the pointer has a proper value then no action is taken

    and execution continues at the next instruction.

    This procedure does not alter any of the window, menu or

    USER saved screen areas wmrec variables or associated

    structure.


      Syntax      : _WMCHK_EXIST(ID,proc);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

    If the ID does not yet exist the programme will abort with

    an error message (see appendix for list).


    proc : string;

    This string should be the name of the function or procedure

    that is calling the _WMCHK_EXIST() procedure, i.e. if say

    a procedure called MYPROC() were to call _WMCHK_EXIST()

    the format should be as follows _WMCHK_EXIST(IDB,'MYPROC');

    Although of course in reality you could use any string you

    want up to a maximum of 255 characters.

    If the string is longer than 255 characters a range check

    error will occure.

.PA

Š      Example     : procedure MYPROC(ID : byte; a,b,c : sometype);

    var

       variables.....

    begin

       _WMCHK_EXIST(ID,'MYPROC');

       remainder

  of

     procedure

statements

    end;


      Rules Notes

      Tips & Traps: No special instructions to be observed.

.PA

Š      ------------------------------------------------------------------------

      _WMCHK_MEM()                                                _WMCHK_MEM()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the following functions and

      Low Level     procedures:- NEW_WIN(), NEW_MENU(), MBAR_COMMENT(),

    WMSAVE_SCR().

       This procedure checks to see if there is enough

    contigous free memory space available for the calling

    procedure to allocate a new dynamic variable of size

    "blk_reqd".

       If there is then no action is taken and control is

    returned to the calling routine.

       If there are no memory blocks large enough then the

    current programme will be aborted with an error message to

    that effect (see appendix for list).

       The procedure actualy checks to see if blk_reqd >

    maxavail (maxavail is the Turbo function which returns the

    size of the largest contigous block of memory, as opposed

    to the Turbo function memavail which returns the total

    amount of free ram available in all free blocks).

       Please refer also to the Turbo Pascal version note

    section and the section for owners of the Winmen source

    files below.


      Syntax      : _WMCHK_MEM(proc,blk_reqd);


      Variables   : proc : string;

    This string should be the name of the function or procedure

    that is calling the _WMCHK_MEM() procedure, i.e. if say

    a procedure called MYPROC() were to call _WMCHK_MEM()

    the format should be as follows _WMCHK_MEM(2048,'MYPROC');

    Although of course in reality you could use any string you

     want up to a maximum of 255 characters.

    If the string is longer than 255 characters a range check

    error will occure.                                        


    blk_reqd : word;

    This word value is the size of block of contigous memory 

    that the calling routine requires.

    This must be a value in the range 0-65535 or a range check

    error will occure.                                        


      Example     : procedure MYPROC(ID : byte; a,b,c : sometype);

    var

       variables.....

    begin

       _WMCHK_MEM('MYPROC',57632);

       remainder

  of

    procedure

statements

    end;                                                      

.PA

Š      Turbo Pascal

      Version Note: The freelist records for TP V5.X used to be grouped

    together in 8 byte records, starting at heapend and

    growing downwards into free memory, as each new record was

    added, the system variable Freeptr used to point to the

    end of the list, each record was made up of two fields,

    blk_org and blk_end, each one was a normalised pointer

    value, giving the starting and ending addresses of each

    free block in the programmes heap, a free block, or hole,

    is created in the heap each time a dynamic variable is

    disposed of using either freemem() or the dispose()

    procedures, the freelist records keep track of all these

    blocks.

       With the freelist records being in a block, on there

    own, at the top of ram, made them extremley dificult to

    overwrite.

       The freelist records for TP V6.0 are no longer grouped

    together, they are now each attached to there respective

    free blocks of ram in the programmes heap, they occupy the

    first 8 bytes of each free block. The two fields have

    also changed, they are now, next and size, both are still

    normalised pointers, the next field points to the next

    freeblock and record, and the size field gives the size of

    the free block.  The first freeblock is pointed to by the

    Freelist pointer variable, the Freeptr variable is no

    longer used.

       With this type of structure it becomes very easy in

    deed to overwrite the freelist record at the start of a

    particular block.  This could occure if, for instance,

    getmem() were called to allocate memory for part of a

    dynamic array.  If the array had 10 elements and we knew

    we were only ever going to use 5 of them, we could, to

    save space, allocate just enough memory for the 5, if we

    then, by mistake, use elements 6,7,8,9 and this would be

    quite legal, as we are still in range for the array index,

    we could in fact be overwriting the record belonging to

    another free block. This could occure if the free block

    allocated for the array was previously a hole in the

    programmes heap with a very small data area above it and

    then another hole in the heap above that, before the next

    chunk of data, the array elements 6,7,8, and 9 would

    overwrite both the small data area and the freelist record

    for that next free hole, the maxavail() function will fail

    when its search reaches the free hole that has just had

    its record overwritten, the value for the next field will

    be a load of old rubbish, sending maxavail() into outer

    space. This could also of occured by just allocating

    insufficient space for a structure in the call to

    getmem(), by mistake.

       Of course there is no excuse for poor or inaccurate

    programming, but at least the memory management system for

    TP V5.X did give us a small, but very greatfull margin to

    play with. From now on you had better make sure that

    every call to getmem() is bit perfect.

.PA

Š      For Owners

      Of Winmen

      Source Files: In case you are having trouble finding where your

    programme is stuck, due to the problem explained above, we

    have included another version of the _WMCHK_MEM();

    procedure in the WMCOMON2.PRS source file, to compile this

    version, instead of the standard one, all you need to do

    is delete the $ character from the {$DEFINE

    STANDARD_WMCHK_MEM} compiler statement and insert a $

    character in the {DEFINE SPECIAL_WMCHK_MEM} complier

    statement and recompile the Winmen Unit, due to some of

    the routines used in the above procedure, it will only

    compile with TP V6.X.

       It does its own free block checking and pointer

    chasing, in, I guess, much the same way as maxavail()

    does, only this one counts each pointer it has chased in

    the loop, if it reaches 10000, it will abort with an

    informative error message, as it's going to be very

    unlikely that any application will produce more than 10000

    holes in the heap, it's more likely that the above

    situation has occured. This gives us a gracefull exit,

    instead of having to ctrl, alt, del.

       Also refer to the description of the WMMEM_STAT();

    procedure for further information.


      Rules Notes

      Tips & Traps: There are no other special instruction to be observed

    for this procedure other than thoes above.

.PA

Š      ------------------------------------------------------------------------

      _WMCHK_TYPE()                                              _WMCHK_TYPE()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the following functions and

      Low Level     procedures:- LIST_MENU(), POP_MENU(), BAR_MENU(),           

    MPIC_COL(), MBAR_COMMENT(), MCHANGE_CHAR(), WOPEN(), 

    WSELECT(), WCLRSCR(), WCOLOUR(), infact you will notice

    that it is called by all routines that take an ID as the

    first argument and which are not common to both windows and

    menus and are also high level routines ie. routines that 

    are specific to windows or menus and are most likely to be

    called by the end user.

    All the above routines call this procedure to make sure 

    that the window/menu ID, sent by the user, is compatible

    with that routine and what it is going to be doing with

    that IDBs record and associated data, ie. is the user

    trying to POP or LIST a window or maybe WOPEN a menu ?

    This is possible because windows and menus use the same

    array of pointers (ID_WM[]) to address there records, as

    there record type is exactly the same. What the procedure

    actualy does is to compare the "typ" parameter char with 

    the "ID^.typ" char in that IDBs record, if they match then 

    the user is deemed to have sent a compatible ID to that

    particular procedure, if they do not match then they are

    incompatible and the programme will be aborted with an

    error message (see appendix for list). This obviously

    makes sense in the context in which I have used it, but

    it will probably be of very limited use to an end user

    unless he/she has a specific use for it, similar to this.

    No window, menu or user saved screens records or associated

    date are affected by this procedure.

    No checks are carried out on the validity of data supplied

    to this low level procedure, so extra care is needed.               


      Syntax      : _WMCHK_TYPE(ID,proc,typ);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

    If the ID does not yet exist then the results could be 

    unpredictable.                                             

.PA

Š     proc : string;

    This string should be the name of the function or procedure

    that is calling the _WMCHK_TYPE() procedure, i.e. if say

    a procedure called MYPROC() were to call _WMCHK_TYPE() the

    format should be as follows _WMCHK_TYPE(ID,'MYPROC','M');

    Although of course in reality you could use any string you

    want up to a maximum of 255 characters.

    If the string is longer than 255 characters a range check

    error will occure.                                        

  

    typ : char;

    This character should normaly be either a 'M' or 'W'

    for the application in which I have used the procedure

    and denotes weather the routine, in which the _WMCHK_TYPE()

    procedure has been put, is specific to just windows or just

    menus. It will be used to check against the supplied IDs

    record variable "ID^.typ", as explained above.


      Example     : procedure MENU_PROC(ID : byte; a,b,c : sometype);

    var

       variables.....

    begin

       _WMCHK_TYPE(ID,'MENU_PROC','M');

       remainder

  of

    procedure

statements

    end;                                                      


      Rules Notes

      Tips & Traps: No special instructions to be observed.                   

.PA

Š      ------------------------------------------------------------------------

      _WMCOPY_SCR()                                              _WMCOPY_SCR()

      ------------------------------------------------------------------------ 


      Procedure   : Copy the area of screen bounded by the supplied l1,t1,r,b

      Low Level     values, to the position specified by the supplied l2,t2

                    values, the width (r-l1) and height (b-t1) will be the

    same as the area being copied.

       No checks are carried out on the validity of data 

    supplied to this low level procedure, so extra care is 

    needed.

       The objects wmrec is not affected by this procedure.        

       This procedure is not called by any of the routines 

    in the Winmen Unit. 


     Syntax       : _WMCOPY_SCR(l1,t1,r,b,l2,t2);


     Variables    : l1 : byte; (B1_80)

    Leftmost edge of the screen area to be saved, must be a 

    value between 1-80 or a range check error will occure.

 

    t1 : byte; (B1_25)

    Topmost edge of the screen area to be saved, must be a 

    value between 1-25 or a range check error will occure.

 

    r : byte; (B1_80)

    Rightmost edge of the screen area to be saved, must be a 

    value between 1-80 or a range check error will occure.


    b : byte; (B1_25)

    Bottommost edge of the screen area to be saved, must be a 

    value between 1-25 or a range check error will occure.     


    l2 : byte; (B1_80)

    New column at which to position the leftmost edge of the 

    screen area to be copied, must be a value between 1-80 or 

    a range check error will occure.

 

    t2 : byte; (B1_80)

    New row at which to position the topmost edge of the 

    screen area to be copied, must be a value between 1-25 or 

    a range check error will occure.


      Example     : program _WMCOPSC;


    uses crt,dos,winmen;

.PA

Š     begin

       clrscr;

       writeln('Some text to copy to another');

       writeln('part of the screen.');

       writeln('As you can see, it can be wrapped');

       writeln('around the screen as well');

       writeln;

       write('<RET> to copy text....');

       readln;

       _WMCOPY_SCR(1,1,33,4,40,1);    {*COPY AREA OF SCREEN*}

       write('<RET> to copy text....');

       readln;

       _WMCOPY_SCR(1,1,33,4,40,8);    {*COPY AGAIN*}

       write('<RET> to wrap text around screen....');

       readln;

       _WMCOPY_SCR(1,1,33,4,65,15);   {*COPY IT PART OFF SCR*}

       write('<RET> to continue....');

       readln;

    end.


      Rules Notes

      Tips & Traps: Just one interesting point here, as you will notice from 

    the example, if you specify a new top left position, for 

    the screen area to be copied to, which effectively then 

    puts some of the text off the right hand edge of the 

    screen, the remainder of each line of text will appear 

    on the left hand side of the screen and on the next 

    line. This is because screen ram is a linear block of 

    memory, with character position 1,1 being at offset zero 

    [VIDEO:0000/0001], a character position of 80,1 would be 

    at offset [VIDEO:0159/0160], and character position 1,2, 

    which is the first character on the next line, is at 

    offset [VIDEO:0161/0162], which is the next pair of linear 

    addresses in screen ram. As you have probably already 

    guessed the _WMCOPY_SCR() procedure writes directly to 

    screen ram in a linear fashion, producing the wrapping 

    effect in the example.   

       For more information on the VIDEO segment addresses 

    refer to the scctions on "Winmen Declared Global 

    Variables" and "Winmen Initialisation". 

       Each screen character cell occupies one word (2 Bytes)

    of screen ram, for more information see the sub-section on 

    the mmenu type in the "Winmen Declared Types" section.

.PA

Š      ------------------------------------------------------------------------

      _WMDEL_MREC()                                              _WMDEL_MREC()

      ------------------------------------------------------------------------ 

      

      Procedure   : Delete the maprec, for the object specified by ID,(window,

      Low Level     menu or user screen), at the 3D screen map location 

    indicated by map_inx. 

       Once the maprec has been sucessfuly deleted, the 

    memory occupied by it is returned to the heap for reuse. 

       If the maprec deleted was in the middle of a list, the 

    maprec above is automaticaly linked to the maprec below, 

    i.e the "next" pointer field of the maprec below is given 

    the address of the record above.

       If the maprec deleted was on the end of a list then the 

    "next" pointer field of the maprec below is given nil, to 

    indicate that this record is now the last one in the list.

       If the maprec deleted was the first in the list then 

    the 3D screen map array pointer at location MAP[map_inx] 

    is given either nil, if there are no other records in the 

    list, or the address of the maprec above.

       This routine assumes that a maprec will be present in 

    the list, for the given object, at location map_inx, if 

    one does not the routine will hang the system.  

       The objects ID must have been previously created using 

    NEW_WIN() or NEW_MENU().

       No checks are carried out on the validity of data 

    supplied to this low level procedure, so extra care is 

    needed.

       The objects wmrec is not affected by this procedure.        

       This procedure is called by:- WMDEL_MREC_ALL();


      Syntax      : _WMDEL_MREC(ID,map_inx);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or 

    user saved screen area, as returned from NEW_MENU() or 

    NEW_WIN() and as sent to WMSAVE_SCR(0-19), if it is a user 

    saved screen area.

       If the ID does not yet exist the results will be 

    unpredictable, as the ID is not checked.                   


    map_inx : word;

    This is the 3D screen map location index, (MAP[map_inx])

    at which the maprec, for the specified object ID, is to be 

    deleted.  


      Example     : procedure _DELRECS(ID);


    var

       ncol,nrow : byte;

       mapinx,map_inx,sc_inx : word; 

       IDWM : pt_wmrec;

.PA

Š     begin

       IDWM := ID_WM[IDB];            {*GET POINTER TO WMREC*}

       nrow := num rows in object     {*CALC ROWS & COLS*}

       ncol := num cols in object 

       mapinx := top left char posn   {*CALC MAP ARRAY INDEX*}

       sc_inx := 0;                   {*W/M SCREEN ARRAY INX*}

       for each row in object do      {*FOR EACH ROW IN OBJ*}

       begin

  map_inx := mapinx;          {*UPDATE MAP COL INDEX*}

  for each column in row do   {*FOR EACH COL IN ROW*}

  begin                       {*ADD A RECORD TO MAP*}

     _WMDEL_MREC(ID,map_inx);

     inc map_inx to next column{*INC MAP ROW INDEX*}

     inc sc_inx to next column{*INC OBJ SCR ARY INX*}

  end;                        {*INC TO NEXT ROW*}

  inc mapinx to start of next row

       end;

    end {_DELRECS};


      Rules Notes

      Tips & Traps: The above example, in a mixture of Pascal and psuedo code,

    shows how to delete a complete maprec structure from the

    3D screen map, for any given object (window, menu or user 

    screen). 

       The example, in common with any of the Windows and Menus

    low level routines, does not carry out any checking on the 

    parameters supplied to it by the user.  There would also 

    normaly be quite a few internal checks caried out, for 

    instance, to make sure that maprecs do exist at the 

    location indicated by map_inx, prior to the _WMDEL_MREC(); 

    procedure trying to do a delete, this will prevent the 

    scenario outlined in the procedure description from 

    happening, this would usualy be done by a preceding high 

    level type routine, along with other checks.  

       As with any routine that uses pointers and allocates or 

    deallocates memory, as does _WMDEL_MREC(); great care needs

    to be taken and in particular checks needs to be carried 

    out prior to its use.

.PA

Š      ------------------------------------------------------------------------

      _WMREST_SCR()                                               WMREST_SCR()

      ------------------------------------------------------------------------


      Procedure   : Restore, to the area of screen bounded by the supplied 

      Low Level     l,t,r,b values, the data in an array of type "screen" 

    which is pointed to by a pointer of type "pt_scr". 

       For details of the "screen" and "pt_scr" types, which 

    are Winmen declared data types, see the section titled 

    "Winmen Declared Types", in chapter 2.

       No checks are carried out on the validity of data 

    supplied to this low level procedure, so extra care is 

    needed.

       The objects wmrec is not affected by this function.  

       This function is called by:- WMMOVE(); and WMOPEN();    


      Syntax      : _WMREST_SCR(my_area,l,r,t,b);


      Variables   : l : byte; (B1_80)

    Leftmost edge of the window including border, must be a

    value between 1-80 or a range check error will occure.

 

    t : byte; (B1_25)

    Topmost edge of the window including border, must be a

    value between 1-25 or a range check error will occure.

 

    r : byte; (B1_80)

    Rightmost edge of the window including border, must be a

    value between 1-80 or a range check error will occure.


    b : byte; (B1_25)

    Bottommost edge of the window including border, must be a

    value between 1-25 or a range check error will occure.

      

    my_area : pt_scr;

    This is the pointer value that was returned when the 

    _WMSAVE_SCR(); function was called and is the starting 

    address of the block of memory allocated to hold the 

    screen area bounded by the supplied l,t,r,b values. The 

    area is stored in screen ram format.

       For a full explanation of the "pt_scr" type refer to

    section titled "Winmen Declared Types" in chapter one.     


      Example     : program _WMRESSC;


    uses crt,dos,winmen;


    var

       my_area : pt_scr;

.PA

Š     begin                             {*WRITE SOME TEXT*}

       clrscr;

       writeln('We will put a few lines of text'); 

       writeln('on the screen so we can copy the');

       writeln('screen to another position.');

       my_area := _WMSAVE_SCR(1,1,32,3);

       gotoxy(1,9);                   {*SAVE SCREEN AREA*}

       write('<RET> key to copy area2 = area1, wid/hgt same');

       readln;

       _WMREST_SCR(my_area,35,19,66,21);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to copy area2 > area1....');

       readln;

       _WMREST_SCR(my_area,35,2,75,6);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to copy area2 = area1, wid/hgt not =');

       readln;

       _WMREST_SCR(my_area,4,18,15,25);

       writeln;                       {*RESTOR SCREEN AREA*}

       write('<RET> key to continue....');

       readln;

    end.


      Rules Notes

      Tips & Traps: The example will effectively copy the area of screen

    bounded by 1,1,32,3 to the new area 35,15,67,17. In this

    example the two areas have exactly the same width and

    height, it is important that the area you restore is the

    exact same size as the one you saved, although you could

    of course specify a diferent width and or height, as long

    as area1 = area2. If area2 is < area1 then no harm will

    come, you will just get less of the original text in the

    new position. As the "screen" array type that "pt_scr"

    points to is a linear array, it will be the later part of

    the text that will be missing. If area2 is > area1 the

    extra (area2-area1) that will be restored will just be

    whatever data exists in memory above the block reserved

    for the "my_area" screen array, probably rubbish.          

.PA

Š      ------------------------------------------------------------------------

      _WMSLIDE_D()                                                _WMSLIDE_D()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the folowing functions and

      Low Level     and procedures:- WMSLIDE().

       This procedure facilitates the sliding of an existing

    text window, menu or user saved screen area (ID<20) plus

    its contents nchar(s) downwards.

       The objects record is then updated with its new

    position.

       The new area underneath the object is then saved away

    into the objects ID_SC[] background "screen" array,

    replacing the previous image data.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.

       For more information on sliding please refer to the

    section covering the WMSLIDE(); procedure.


      Syntax      : _WMSLIDE_D(ID,nchar,l,t,r,b,ncol,nrow);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

       If the ID does not yet exist then the results could be

    unpredictable, as no checks are carried out.


    nchar : byte; (B1_25)

    This is the number of characters or lines that the menu,

    window or USER saved screen area will be moved in a

    downwards direction. Must be a value in the range:-

    1-(number of lines left between the botom of window/

    menu/USER area and the bottom of the screen). If this

    rule is not adhered to the results could and probably

    will be unpredictable, resulting possibly in a crash of

    your programme. If the value supplied is outside the

    range 1-25 then the programme will abort with a range

    check error

       Normaly of course these low level type routines are

    called from a high level routine, in this case WMSLIDE(),

    which takes care of all the checks reqd on the data

    suplied to the low level routine, so as mentioned above a

    great deal more care is required.

.PA

Š     l : byte; (B1_80)

    Leftmost edge of the win/menu/user including border, must

    be a value in the range 1-80 or the programme will abort

    with a range check error.

       This would normaly be the '.l' field of the objects

    wmrec.


    t : byte; (B1_25)

    Topmost edge of the win/menu/user including border, must

    be a value in the range 1-25, or the programme will abort

    with a range check error.

       This would normaly be the '.t' field of the objects

    wmrec.


    r : byte; (B1_80)

    Rightmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.r' field of the objects

    wmrec.


    b : byte; (B1_25)

    Bottommost edge of the win/menu/user including border,

    must be a value in the range 1-25, or the programme will

    abort with a range check error.

       This would normaly be the '.b' field of the objects

    wmrec.


    ncol : byte; (B1_80)

    This value is the absolute number of columns that the 

    window, menu or USER saved screen area covers or its

    width (r-l+1). Must be a value in the range 1-80, or the

    programme will abort with a range check error.

    

    nrow : byte; (B1_25)

    This value is the absolute number of rows that the

    window, menu or USER saved screen area covers or its

    depth (b-t+1). Must be a value in the range 3-25, or the

    programme will abort with a range check error.


       The example below covers all of the low level slide

    procedures:- _WMSLIDE_U(), _WMSLIDE_D(), _WMSLIDE_L() and

    _WMSLIDE_R().


      Example     : program SLI_UDLR;


    var

       m1,m1c,l,t : byte;            {*DEFINE GLOBALS*}

       mt : pt_mtext;

       ID : pt_wmrec;

.PA

Š     begin

       getmem(mt,4*81);              {*DEFINE MENU*}

       mt^[1] := '8) Slide Up';

       mt^[2] := '4) Slide Left';

       mt^[3] := '6) Slide Right';

       mt^[4] := '2) Slide Down';

       m1 := NEW_MENU(1,4,14,7,0,,1,mt,4);

       freemem(mt,4*81);


       l := 32;                      {*INIT VARBS*}

       t := 9;

       m1c := 10;

       ID := ID_WM[m1];

       WMTITLE(m1,1,15,'SLIDE ME');  {*DO TITLE STRING*}


       while not(m1c in[0]) do       {*WHILE NOT ESCAPE*}

       begin

  m1c := POP_MENU(m1,l,t);

  case m1c of

     1 : if(t > 1) then      {*MOVE MENU UP 1 ROW*}

begin

    dec(t);

    _WMSLIDE_U(m1,1,ID^.l,ID^.t,ID^.r,ID^.b,

      (ID^.r-ID^.l+1),(ID^.b-ID^.l+t));

end;

     2 : if(l > 2) then      {*MOVE MENU LEFT 1 COL*}

begin

    dec(l,2);

    _WMSLIDE_L(m1,2,ID^.l,ID^.t,ID^.r,ID^.b,

      (ID^.r-ID^.l+1),(ID^.b-ID^.l+t));

end;

     3 : if(ID_WM[m1]^.r+2 < 80) then

begin               {*MOVE MENU RIGHT 1 COL*}

    inc(l,2);

    _WMSLIDE_R(m1,2,ID^.l,ID^.t,ID^.r,ID^.b,

      (ID^.r-ID^.l+1),(ID^.b-ID^.l+t));

end;

     4 : if(ID_WM[m1]^.b+1 < 25) then

begin               {*MOVE MENU DOWN 1 ROW*}

    inc(t);

    _WMSLIDE_D(m1,1,ID^.l,ID^.t,ID^.r,ID^.b,

      (ID^.r-ID^.l+1),(ID^.b-ID^.l+t));

end;

  end {case};

       end {while};

       normvideo;

    end {WM_SLIDE}.                                           

.PA

Š      Rules Notes

      Tips & Traps: The above example shows quite clearly how to use each of

    the low level slide procedures, of course extra care must

    be taken to ensure that only valid data is fed to the

    slide procedures,or in fact any of the low level procedures

    as no checking whatsoever is carried out on perameter data

    passed to the procedure, by the user, this is clearly the

    users responsability, as normaly all perameter data 

    checking is done by the high level procedures.

       The screen area which comprises the window, menu or

    USER saved screen area, is actualy slid in the following

    sequence of events:-


    a) The screen character data immediatly in front of the

       window/menu to be moved, is saved away in a temporary

       storage array to protect it from the leading edge of

       the window/menu.


    b) The screen block which is the window/menu is then moved

       or reshuffled the specified number of characters in the

       specified direction, this is simply a move within the

       screen ram area.


    c) The screen character data that was under the trailing

       edge of the window/menu, before it was moved in (b), is

       now put back into screen ram from the window/menu

       screen array, this completes the slide and restores the

       screen under the window/menu to the condition it was in

       prior to the window/menu covering it up.


    d) Finaly but most importantly, the cleaver bit.  The

       menu/ window screen array (char data from under that

       area) is now restacked or reshuffled so that the screen

       character data from (a), which is in its temporary

       storage array, is placed in the correct position,

       column or row, depending on the direction of the slide,

       in that menu or windows screen array, as you can

       imagine this involves guite a bit of juggling to

       achieve.


    Well that at least should give you some idea of how things

    are done without giving too many secrets away.

.PA

Š      ------------------------------------------------------------------------

      _WMSLIDE_L()                                                _WMSLIDE_L()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the folowing functions and

      Low Level     and procedures:- WMSLIDE().

       This procedure facilitates the sliding of an existing

    text window, menu or user saved screen area (ID<20) plus

    its contents nchar(s) leftwards.

       The objects record is then updated with its new

    position.

       The new area underneath the object is then saved away

    into the objects ID_SC[] background "screen" array,

    replacing the previous image data.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.

       For more information on sliding please refer to the

    section covering the WMSLIDE(); procedure.


      Syntax      : _WMSLIDE_L(ID,nchar,l,t,r,b,ncol,nrow);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

       If the ID does not yet exist then the results could be

    unpredictable, as no checks are carried out.


    nchar : byte; (B1_80)

    This is the number of characters or lines that the menu,

    window or USER saved screen area will be moved in a

    downwards direction. Must be a value in the range:-

    1-(number of lines left between the left of the window/

    menu/USER area and the left edge of the screen). If this

    rule is not adhered to the results could and probably

    will be unpredictable, resulting possibly in a crash of

    your programme. If the value supplied is outside the

    range 1-80 then the programme will abort with a range

    check error

       Normaly of course these low level type routines are

    called from a high level routine, in this case WMSLIDE(),

    which takes care of all the checks reqd on the data

    suplied to the low level routine, so as mentioned above a

    great deal more care is required.

.PA

Š     l : byte; (B1_78)

    Leftmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.l' field of the objects

    wmrec.


    t : byte; (B1_25)

    Topmost edge of the win/menu/user including border, must

    be a value in the range 1-25, or the programme will abort

    with a range check error.

       This would normaly be the '.t' field of the objects

    wmrec.


    r : byte; (B1_80)

    Rightmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.r' field of the objects

    wmrec.


    b : byte; (B1_25)

    Bottommost edge of the win/menu/user including border,

    must be a value in the range 1-25, or the programme will

    abort with a range check error.

       This would normaly be the '.b' field of the objects

    wmrec.


    ncol : byte; (B1_80)

    This value is the absolute number of columns that the

    window, menu or USER saved screen area covers or its

    width (r-l+1). Must be a value in the range 1-80, or the

    programme will abort with a range check error.

    nrow : byte; (B1_25)

    This value is the absolute number of rows that the

    window, menu or USER saved screen area covers or its

    depth (b-t+1). Must be a value in the range 1-25, or the

    programme will abort with a range check error.


      Example     : The example for _WMSLIDE_D() covers all of the low level 

    slide procedures:- _WMSLIDE_U(), _WMSLIDE_D(), _WMSLIDE_L()

    and _WMSLIDE_R().                                         


      Rules Notes

      Tips & Traps: The above example shows quite clearly how to use each of

    the low level slide procedures, of course extra care must

    be taken to ensure that only valid data is fed to the

    slide procedures,or in fact any of the low level

    procedures as no checking whatsoever is carried out on

.PA

Š     perameter data passed to the procedure, by the user, this

    is clearly the users responsability, as normaly all

    perameter data checking is done by the high level

    procedures. The screen area which comprises the window,

    menu or USER saved screen area, is actualy slid in the

    following sequence of events:-


    a) The screen character data immediatly in front of the

       window/menu to be moved, is saved away in a temporary

       storage array to protect it from the leading edge of

       the window/menu.


    b) The screen block which is the window/menu is then moved

       or reshuffled the specified number of characters in the

       specified direction, this is simply a move within the

       screen ram area.


    c) The screen character data that was under the trailing

       edge of the window/menu, before it was moved in (b), is

       now put back into screen ram from the window/menu

       screen array, this completes the slide and restores the

       screen under the window/menu to the condition it was in

       prior to the window/menu covering it up.


    d) Finaly but most importantly, the cleaver bit. The

       menu/window screen array (char data from under that

       area) is now restacked or reshuffled so that the screen

       character data from (a), which is in its temporary

       storage array, is placed in the correct position,

       column or row, depending on the direction of the slide,

       in that menu or windows screen array, as you can

       imagine this involves guite a bit of juggling to

       achieve.


    Well that at least should give you some idea of how things

    are done without giving too many secrets away.

.PA

Š      ------------------------------------------------------------------------

      _WMSLIDE_R()                                                _WMSLIDE_R()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the folowing functions and

      Low Level     and procedures:- WMSLIDE().

       This procedure facilitates the sliding of an existing

    text window, menu or user saved screen area (ID<20) plus

    its contents nchar(s) rightwards.

       The objects record is then updated with its new

    position.

       The new area underneath the object is then saved away

    into the objects ID_SC[] background "screen" array,

    replacing the previous image data.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.

       For more information on sliding please refer to the

    section covering the WMSLIDE(); procedure.


      Syntax      : _WMSLIDE_R(ID,nchar,l,t,r,b,ncol,nrow);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

       If the ID does not yet exist then the results could be

    unpredictable, as no checks are carried out.


    nchar : byte; (B1_80)

    This is the number of characters or lines that the menu,

    window or USER saved screen area will be moved in a

    downwards direction.  Must be a value in the range:-

    1-(number of lines left between the right edge of window/

    menu/USER area and the right edge of the screen). If this

    rule is not adhered to the results could and probably will

    be unpredictable, resulting possibly in a crash of your

    programme.  If the value supplied is outside the range

    1-80 then the programme will abort with a range check

    error

       Normaly of course these low level type routines are

    called from a high level routine, in this case WMSLIDE(),

    which takes care of all the checks reqd on the data

    suplied to the low level routine, so as mentioned above a

    great deal more care is required.

.PA

Š     l : byte; (B1_80)

    Leftmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.l' field of the objects

    wmrec.


    t : byte; (B1_25)

    Topmost edge of the win/menu/user including border, must

    be a value in the range 1-25, or the programme will abort

    with a range check error.

       This would normaly be the '.t' field of the objects

    wmrec.


    r : byte; (B1_80)

    Rightmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.r' field of the objects

    wmrec.


    b : byte; (B1_25)

    Bottommost edge of the win/menu/user including border,

    must be a value in the range 1-25, or the programme will

    abort with a range check error.

       This would normaly be the '.b' field of the objects

    wmrec.


    ncol : byte; (B1_80)

    This value is the absolute number of columns that the

    window, menu or USER saved screen area covers or its

    width (r-l+1). Must be a value in the range 1-80, or the

    programme will abort with a range check error.

    nrow : byte; (B1_25)

    This value is the absolute number of rows that the

    window, menu or USER saved screen area covers or its

    depth (b-t+1). Must be a value in the range 1-25, or the

    programme will abort with a range check error.


      Example     : The example for _WMSLIDE_D() covers all of the low level 

    slide procedures:- _WMSLIDE_U(), _WMSLIDE_D(), _WMSLIDE_L()

    and _WMSLIDE_R().                                         


      Rules Notes

      Tips & Traps: The above example shows quite clearly how to use each of

    the low level slide procedures, of course extra care must

    be taken to ensure that only valid data is fed to the

    slide procedures,or in fact any of the low level procedures

    as no checking whatsoever is carried out on perameter data

    passed to the procedure, by the user, this is clearly the

.PA

Š     users responsability, as normaly all perameter data 

    checking is done by the high level procedures.

    The screen area which comprises the window, menu or USER

    saved screen area, is actualy slid in the following

    sequence of events:-


    a) The screen character data immediatly in front of the

       window/menu to be moved, is saved away in a temporary

       storage array to protect it from the leading edge of

       the window/menu.


    b) The screen block which is the window/menu is then moved

       or reshuffled the specified number of characters in the

       specified direction, this is simply a move within the

       screen ram area.


    c) The screen character data that was under the trailing

       edge of the window/menu, before it was moved in (b), is

       now put back into screen ram from the window/menu

       screen array, this completes the slide and restores the

       screen under the window/menu to the condition it was in

       prior to the window/menu covering it up.


    d) Finaly but most importantly, the cleaver bit.  The

       menu/ window screen array (char data from under that

       area) is now restacked or reshuffled so that the screen

       character data from (a), which is in its temporary

       storage array, is placed in the correct position,

       column or row, depending on the direction of the slide,

       in that menu or windows screen array, as you can

       imagine this involves guite a bit of juggling to

       achieve.


    Well that at least should give you some idea of how things

    are done without giving too many secrets away.

.PA

Š      ------------------------------------------------------------------------

      _WMSLIDE_U()                                                _WMSLIDE_U()

      ------------------------------------------------------------------------


      Procedure   : Internal procedure called by the folowing functions and

      Low Level     and procedures:- WMSLIDE().

       This procedure facilitates the sliding of an existing

    text window, menu or user saved screen area (ID<20) plus

    its contents nchar(s) upwards.

       The objects record is then updated with its new

    position.

       The new area underneath the object is then saved away

    into the objects ID_SC[] background "screen" array,

    replacing the previous image data.

       No checks are carried out on the validity of data

    supplied to this low level procedure, so extra care is

    needed.

       For more information on sliding please refer to the

    section covering the WMSLIDE(); procedure.


      Syntax      : _WMSLIDE_U(ID,nchar,l,t,r,b,ncol,nrow);


      Variables   : ID : byte;

    The unique identifier for the specified menu, window or

    user saved screen area, as returned from NEW_MENU() or

    NEW_WINDOW() and as sent to WMSAVE_SCR(0-19), if it is a

    user saved screen area.

       If the ID does not yet exist then the results could be

    unpredictable, as no checks are carried out.


    nchar : byte; (B1_25)

    This is the number of characters or lines that the menu,

    window or USER saved screen area will be moved in a

    downwards direction.  Must be a value in the range:-

    1-(number of lines left between the top edge of window/

    menu/USER area and the top edge of the screen). If this

    rule is not adhered to the results could and probably will

    be unpredictable, resulting possibly in a crash of your

    programme.  If the value supplied is outside the range

    1-25 then the programme will abort with a range check

    error

       Normaly of course these low level type routines are

    called from a high level routine, in this case WMSLIDE(),

    which takes care of all the checks reqd on the data

    suplied to the low level routine, so as mentioned above a

    great deal more care is required.

.PA

Š     l : byte; (B1_80)

    Leftmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.l' field of the objects

    wmrec.


    t : byte; (B1_25)

    Topmost edge of the win/menu/user including border, must

    be a value in the range 1-25, or the programme will abort

    with a range check error.

       This would normaly be the '.t' field of the objects

    wmrec.


    r : byte; (B1_80)

    Rightmost edge of the win/menu/user including border, must

    be a value in the range 1-80, or the programme will abort

    with a range check error.

       This would normaly be the '.r' field of the objects

    wmrec.


    b : byte; (B1_25)

    Bottommost edge of the win/menu/user including border,

    must be a value in the range 1-25, or the programme will

    abort with a range check error.

       This would normaly be the '.b' field of the objects

    wmrec.


    ncol : byte; (B1_80)

    This value is the absolute number of columns that the

    window, menu or USER saved screen area covers or its

    width (r-l+1). Must be a value in the range 1-80, or the

    programme will abort with a range check error.

    nrow : byte; (B1_25)

    This value is the absolute number of rows that the

    window, menu or USER saved screen area covers or its

    depth (b-t+1). Must be a value in the range 1-25, or the

    programme will abort with a range check error.


      Example     : The example for _WMSLIDE_D() covers all of the low level 

    slide procedures:- _WMSLIDE_U(), _WMSLIDE_D(), _WMSLIDE_L()

    and _WMSLIDE_R().                                         


      Rules Notes

      Tips & Traps: The above example shows quite clearly how to use each of

    the low level slide procedures, of course extra care must

    be taken to ensure that only valid data is fed to the

    slide procedures,or in fact any of the low level procedures

    as no checking whatsoever is carried out on perameter data

    passed to the procedure, by the user, this is clearly the

.PA

Š     users responsability, as normaly all perameter data 

    checking is done by the high level procedures.

    The screen area which comprises the window, menu or USER

    saved screen area, is actualy slid in the following

    sequence of events:-


    a) The screen character data immediatly in front of the

       window/menu to be moved, is saved away in a temporary

       storage array to protect it from the leading edge of

       the window/menu.


    b) The screen block which is the window/menu is then moved

       or reshuffled the specified number of characters in the

       specified direction, this is simply a move within the

       screen ram area.


    c) The screen character data that was under the trailing

       edge of the window/menu, before it was moved in (b), is

       now put back into screen ram from the window/menu

       screen array, this completes the slide and restores the

       screen under the window/menu to the condition it was in

       prior to the window/menu covering it up.


    d) Finaly but most importantly, the cleaver bit.  The

       menu/ window screen array (char data from under that

       area) is now restacked or reshuffled so that the screen

       character data from (a), which is in its temporary

       storage array, is placed in the correct position,

       column or row, depending on the direction of the slide,

       in that menu or windows screen array, as you can

       imagine this involves guite a bit of juggling to

       achieve.


    Well that at least should give you some idea of how things

    are done without giving too many secrets away.

.PA

Š       P                      A                       R                      T 

      -----------------------------------------------------------------------

     2






      APPENDICES

.PA

Š      A         P         P         E         N          D         I         X

      ------------------------------------------------------------------------

     A





      ERROR MESSAGES



      The following pages list all the possible error messages that may be

      generated during the run time of a programme that uses the Winmen unit

      and which are, of course, connected only to the Winmen Unit. A brief

      description of the error along with suggested remedial action is also

      included, although the error message its is normaly self explanitary.

      In all the error messages below, where 'NAME' appears, this will be

      replaced by the actual name of the Winmen function or procedure,in which

      the error occured, during the runtime of the programme.

      In all the error messages below, where 'value' appears, this will be

      replaced by an actual integer value, when the message appears during

      the runtime of a programme.

      In all the error messages below, where 'char' appears, this will be

      replaced by an actual character, when the message appears during

      the runtime of a programme.



      Windows Error Messages


      WMMOVE() ERROR:Window Now Goes Off The Screen, Please Check New

      l & t values.

The coordinates supplied to the WMMOVE() procedure, for the new top

lefthand corner of the window, will place the righthand side or the

bottom edge of the window off the screen, this is not allowed.



      NAME() ERROR:Window/Box To Small To Display.


The minimum size for any window or box which is put on the screen is

3x3 screen character cells, any thing less than this will be useless

as there would be no display area.


.PA

Š      Menus Error Messages


      BAR_MENU() ERROR:Option Text+Min Gap Of 1 Between Options Is > blen

      Unable To Display.

      Minimum blen Value For A Min Gap Of 1 Would Be:['value'], For This Menu.


The value you have supplied to the BAR_MENU() function, for the bar 

manu length, is too small to enable all the menu options to be   

displayed, along with the minimum gap of 1 between each option and

before and after the first and last options, you will need to 

increase the bar menu length parameter. The following formula can 

be used to determine the minimum bar menu length :-

sum of all option texts + number options + 1;  



      WMFLOAT() ERROR:Can"t Open Menus From Within This Procedure, Only

      Windows.


A window can be opened from within the WMFLOAT() procedure but a menu

can not. Once a menu is activated we are stuck inside that menu

function until an option is chosen, so we would not return to the

WMFLOAT() procedure, to actualy float the menu to the surface, until

a choice was made, which does seem a bit pointless.



      WMSLIDE() ERROR:Menu not yet open use POP_MENU() Or LIST_MENU().

      Can,t Open a Menu From WMSLIDE().


You have called the WMSLIDE() procedure, for a menu that does exist

but is not yet open. A window can be opened from within the

WMSLIDE() procedure but a menu can not, because once a menu is

activated we are stuck inside that menu function until an option is

chosen, so we would not return to the WMSLIDE() procedure, to actualy

carry out the slide, until a choice was made, which does seem a bit

pointless.



      NAME() ERROR:Menu Goes Off The Screen, Unable To Display.


The coordinates supplied to the NAME() function or procedure, for the 

top lefthand corner of the menu, will place the righthand side or the

bottom edge of the menu off the screen, this is not allowed.                  



      Common Error Messages


      NAME() ERROR:No More Windows+Menus Left, Max is 254.


You are trying to exceed the maximum number of combined windows and

menus available, before you can define any more, you will have to

delete some of the existing ones, that you no langer require, using

WMDELETE().                                                          

.PA

Š

      NAME() ERROR:Record ID Does Not Yet Exist, Or It Has Been DELETED

      Use NEW_WIN(), NEW_MENU() Or WMSAVE_SCR().


The window, menu or user saved screen area identifier 'ID' that you

are using for NAME() function or procedure, has not yet been  

allocated, ie. that object does not exist. Check that you have the

correct one, or if you have, then that object has somehow become

unlinked from its identifier 'ID', most probably you have inadvert-

antly deleted it with WMDELETE(), or one of your own routines that

uses direct memory access techniques, has overwritten some Winmen

record data!



      NAME() ERROR:Not Enough Contigous Memory Left To Create Dynamic

      Variable.


The NAME() function or procedure is unable to allocate enough memory

to carry out an essential operation, so execution is terminated. 

In other words you have run out of ram memory, you may have to get

rid of some windows or menus which are not required.



      NAME() ERROR:ID Not Compatible With Procedure Type.


The window, menu or user saved screen identifier, which has been

passed to the NAME() function or procedure, was the 'ID' for a menu

when it should have been for a window or vice-versa. Some functions

and procedures are exclusive to either menus or windows, check the

'ID' that you are using.



      _WMCHK_MEM() ERROR:Stuck In Pointer Chasing Loop.

      A Freelist Record, Which Is At The Start Of A Free Block, Has Possibly

      Been Overwritten.

      Tip:- Check all Getmem() Sizes In Your Source Code.


This display of this error message depends on which version of the

_WMCHK_MEM(); procedure you have compiled, for full details please

refer to the section on the _WMCHK_MEM(); procedure.


      WMMEM_STAT() ERROR:'errstr'

possibles for 'errstr':-

    Path Not Found.

    Too Many Open Files.

    File Access Denied.

    File Not Assigned.

    Invalid Parameter r_a='char', Must Be:- A,a,R or r.


Path Not Found. The name assigned to a file variable is invalid or

specifies an unexisting subdirectory.

.PA

Š Too Many Open Fles. The programme has too many open files, check that

the config.sys file in the root directory has enough FILES=nnn speci-

fied for this particular application.


File Access Denied. The file assigned to a file variable does not

have write access, This will only occure if the file assigned to

the file variable, was not created by the WMMEM_STAT() procedure,

but by another routine, and only posseses read accesss rights.


File Not Assigned. The file variable has not been assigned a name

through a call to Assign().


Invalid Parameter. The r_a parameter in the call to WMMEM_STAT() is

incorrect, it can only be one of the following:-

'R', 'r', 'A' or 'a'.



      WMREST_SCR() ERROR:The New Requested Screen Area For This Window,

      Menu Or User Screen Is Larger Than The Existing One, It Must Be The

      Same Size Or Less.


It is not possible to redisplay an area of screen, from an objects

ID_SC[] background "screen" array, that is larger than the one

originaly saved away, doing so would cause corruption of part or all

of the screen, by data belonging to somthing else.


      WMSAVE_SCR() ERROR:The new Requested Screen Area For This Window Or

      Menu Is Larger Than The Existing One, It must be The Same Size Or Less.


You can't put a quart into a pint pot, if the new requested area of

screen to be saved away, into an objects ID_SC[] background "screen"

array, was larger that the original, it would over-write data

belonging to somthing else, with disasterous consequences.



      WMSAVE_SCR() ERROR:The Window Or Menu, For Which You Are Trying To

      Replace The Background Screen Area Is Closed. This Is An Invalid

      Operation.


This is an invalid operation because the ID_SC[] background "screen"

array that you are trying to replace, for the object specified by ID,

will be overwritten the next time that object is opened for use, as

all Winmen routines that activate objects call WMSAVE_SCR() before

they actualy open the object for use.


.PA

Š      WMSLIDE() ERROR:Window/Menu Will Slide Off Screen, Reduce Nchar Value.


The leading edge of the window, menu or user saved screen area will

go off the screen, if that particular value is used for the nchar

parameter in the call to WMSLIDE() procedure. Chech the number of

characters to slide value and reduce it.



      WMTITLE() ERROR:Title too long, max for this window/Menu is:['value']

      chars.


The title string you have specified in the call to WMTITLE() is too

long to be displayed in the space available at the top of the window

menu or user saved screen. The title string should not be longer than

the width of the object, including the border, minus 4 characters.



Comments

Popular posts from this blog

BOTTOM LIVE script

Fawlty Towers script for "A Touch of Class"