.PO 0
.PL 66
WINDOWS AND MENUS, FOR TURBO PASCAL
------------------------------------------------------------------------
REFERENCE GUIDE
VERSION 1.5
BY G.R.DYKE
(c)1990
.PA 2
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 3
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
.PA 4
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
Common 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 5
_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 6
THIS PAGE LEFT INTENTIONALLY BLANK
.PA 7
P A R T
------------------------------------------------------------------------
1
PROGRAMMER'S REFERENCE
.PA 8
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.
.PA 9
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
supplied on page 10 of this manual. Please also include œ1
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
.PA 10
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
in your programme and also offers advice on what to do about it.
>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 11
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 12
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 13
>>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 14
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 : -|
Full colour chart
CGA MDA
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
Chart of usefull box type Ascii values
Dec | 169 170 179 180 181 182 183 184 185 186 187 188 189 190 191
Hex | A9 AA B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
ASCII | © ª ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿
Dec | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
Hex | C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE
ASCII | À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î
Dec | 207 208 209 210 211 212 213 214 215 216 217 218
Hex | CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA
ASCII | Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú
So a screen ram word value of $49B9 would give the character ¹ with
a background colour of red and forground colour of light blue. The
value $49 for the colour byte (low byte) converts to a binary value of
01001001 which is exactly as described above. The $B9 value for the
character byte (high byte) can be referenced in the table above.
It should be clear by now that the 80 words for each of the 402 array
elements is wide enough for a menu the entire width of the screen, the
limitation on the maximum number of lines in a menu will of course be
400 as 2 lines are required for the top and bottom borders of the menu.
We cannot define a type with any more lines in at this width as this now
.PA 15
represents the largest structure we can have in Turbo Pascal, which is
65535 bytes. But dont fear the Windows and Menus unit never actualy
defines a structure of this type directly, only an array of pointers,
(see ID_MM below) each one of which, could eventualy point to a
structure of this type. By using getmem() in conjunction with a pointer
defined as type pt_mmenu (see pt_mmenu below), we can allocate the
minimum amount of memory required for a particular length of menu, in
much the same way as for mtext and pt_mtext (see sections on mtext,
pt_mtext and NEW_MENU() function). We are unable to save ram on the
width as the offset calculated for the start of each 80 word array is
fixed from the begining of the block of ram allocated when getmem() is
used, so we could not just say getmem(ptr,LxWx2), if L=2 and W=25 that
only gives us 50 words, line/array 1 ptr^[1] starts at offset 0 but
line/array 2 ptr^[2] starts at offset 80, this is because the type
definition sayes that each of the 402 array elements accesses an array
of 80 words, as you can see we have exceeded the 50 word block allocated
to us in getmem() possibly overwriting other data. There is no error
either as everything is within range, there would also be no error if
we tried to fill up a 3rd line/array, again disasterous. But the Windows
and Menus unit takes care of all this for you, although you do need to
be carefull when using getmem() and freemem() when used in conjunction
with arrays and pointers to arrays.
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 menu, assuming
that menu has been set up using the NEW_MENU() function:-
IDM^[0..402][0..80] WORDS
[0..80]
0123456789............................................80
0ÉÍÍÍÍÍÍÍÍÍÍÍÍÍ» = IDM^[0][0..15]
1ºOPTION TEXT 1º
ARRAYS 2ºOPTION TEXT 2º --------------------->
[0..402] 3ºOPTION TEXT 3º
4ºOPTION TEXT 4º = IDM^[4][0..15]
5ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ
6 |
7 |
8 |
9 V
The above diagram assumes that you have defined a pointer somewhere in
your programme, like this:-
var
IDM : pt_mmenu; (see pt_mmenu below)
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 menu, assuming the
menu has been set up using NEW_MENU() you would then do the following:-
IDM := ID_MM[ID]; (see ID_MM below)
.PA 16
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 17
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 18
>>.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 : B0_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 19
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 20
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 21
>>.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 22
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 23
>>.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 24
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 25
>>.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 26
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 27
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 28
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ THIS REPRESENTS THE TEXT SCREEN ³
³ =============================== ³
³ ³
³ ³
³ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ³
³ º º ³
³ º THIS IS A TEXT WINDOW, WITH TEXT º ³
³ º IN IT. º ³
³ º º ³
³ º ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ ³
³ º ³ ³ ³
³ º ³ ³ ³
³ º ÚÄÄÄÄÁÄÄÄÄÄÄÄÄÄ¿ ANOTHER TEXT WINDOW WITH ³ ³
³ º ³MENU OPTION 01³ TEXT IN IT. ³ ³
³ º ³MENU OPTION 02³ ³ ³
³ º ³MENU OPTION 03³ ³ ³
³ ÈÍÍÍÍͳMENU OPTION 04³ ³ ³
³ ³MENU OPTION 05³ ³ ³
³ ³MENU OPTION 06³ ³ ³
³ ³MENU OPTION 07³ ³ ³
³ ³MENU OPTION 08³ ³ ³
³ ³MENU OPTION 09³ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³
³ ³MENU OPTION 10³ ³
³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
/\
/ºº\
ºº
ºº A
VIEW ON ARROW 'A'
=================
(Three Level)
MENU ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ
################
################
êêêêêêêêêêêêêêêê (two Level) (Single Level)
TEXT WINDOW êêêêêÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
êêêêê²²²²²²²²²²²ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ
êêêêê#######################################
êêêêê#######################################
êêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêê
TEXT WINDOWÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄêêêêêêêêêêê
ÝÝÝÝÝݲ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²êêêêêêêêêêê
#######################################êêêêêêêêêêê
#######################################êêêêêêêêêêê
êêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêê
ÝÝÝÝÝÝÝÝÝÝݲ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²ÝÝÝÝÝÝÝÝÝÝÝ
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
TEXT SCREEN
.PA 29
LEGEND FOR VIEW ON ARROW 'A':-
##Ý = A "maprec" with the ".next" field = nil;
##² = A "maprec" with the ".next" field = address of next "maprec"
in the linked list;
# = The "maprec" ".ID" field;
# = The "maprec" ".sc_inx" field;
Ý = The "maprec" ".next" field set to nil;
² = The "maprec" ".next" field set to address of next "maprec"
in the linked list;
Using the 3D screen MAP[] array and the associated "maprecs" and
"pt_maprecs".
MAP[] array:-
The 3D screen MAP[] array pointers can be accessed in the following
maner:-
var
map_inx : word;
ptr_to_maprec : pt_maprec;
begin
ptr_to_maprec := MAP[map_inx];
MAP[map_inx] := ptr_to_maprec;
end.
where map_inx is a value in the range 0..2000.
maprecs:-
Any maprecs that have already been created for open objects may be
accessed in the following maner:-
var
pt_rec : pt_maprec;
map_inx,scr_inx : word;
IDB : byte;
begin
IDB := MAP[map_inx]^.ID; \
MAP[map_inx]^.ID := IDB; \
OR \
pt_rec := MAP[map_inx]; \ FOR A SINGLE MAPREC LEVEL
IDB := pt_rec^.ID; / (SEE DIAGRAM ABOVE)
pt_rec^.ID := IDB; /
/
scr_inx := MAP[map_inx]^.sc_inx; /
etc.... /
end; /
.PA 30
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 31
>>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 32
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 33
>>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 34
>>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 35
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 36
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 37
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;
detectgraph(gdriver,gmode); {*GET INSTALLED GRAPHICS CARD DRIVER & MODE*}
case gdriver of {*CHECK DRIVER AGAINST MONO LIST*}
MCGA,HercMono,
EGAMono,-2 : VIDEO := $B000;{*SET VIDEO ADDRESS FOR A MONO TYPE ADAPTER*}
else
VIDEO := $B800; {*SET VIDEO ADDRESS FOR COLOUR TYPE ADAPTER*}
end;
MENU_EXIT_BY_CURSOR := true; {*SET SO POP/LIST MENUS EXITED WITH L/RCURS*}
MENU_ACT_ON_PC := true; {*SET SO IF PIC CHAR SELECT, TAKE ACTION*}
CLOSE_WITH_REMOVE := false; {*SET SO WMCLOSE USES WMFLOAT & REST_SCR*}
end {end unit}.
.PA 38
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 39
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 40
_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 41
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 42
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 43
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 44
WINDOWS AND MENUS FOR TURBO PASCAL
----------------||----------------
WINDOWS FUNCTIONS REFERENCE SECTION
.PA 45
------------------------------------------------------------------------
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).
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).
.PA 46
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 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.
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.
.PA 47
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 48
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 50
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 51
------------------------------------------------------------------------
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 52
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 53
------------------------------------------------------------------------
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 54
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 55
------------------------------------------------------------------------
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 56
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 57
------------------------------------------------------------------------
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 58
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 59
------------------------------------------------------------------------
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 60
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 61
------------------------------------------------------------------------
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 62
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 63
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 64
------------------------------------------------------------------------
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 65
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 66
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 67
------------------------------------------------------------------------
_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 68
verc: word;
Word attribute value for all the vertical characters of
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!).
Low byte first : Colour value. High byte last : ASCII 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
Dec | 169 170 179 180 181 182 183 184 185 186 187 188 189 190 191
Hex | A9 AA B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
ASCII | © ª ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿
Dec | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
Hex | C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE
ASCII | À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î
Dec | 207 208 209 210 211 212 213 214 215 216 217 218
Hex | CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA
ASCII | Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú
.PA 69
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 70
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 71
------------------------------------------------------------------------
_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 72
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 73
------------------------------------------------------------------------
_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 74
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 75
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 76
WINDOWS AND MENUS FOR TURBO PASCAL
----------------||----------------
MENUS FUNCTIONS REFERENCE SECTION
.PA 77
------------------------------------------------------------------------
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 78
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 79
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 80
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 81
------------------------------------------------------------------------
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 82
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 83
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 84
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 85
------------------------------------------------------------------------
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 86
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 87
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 88
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 89
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 90
------------------------------------------------------------------------
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 91
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 92
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 93
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 94
WINDOWS AND MENUS FOR TURBO PASCAL
----------------||----------------
MENUS PROCEDURES REFERENCE SECTION
.PA 95
------------------------------------------------------------------------
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 96
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 97
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 98
------------------------------------------------------------------------
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 99
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 100
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 101
------------------------------------------------------------------------
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 102
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 103
------------------------------------------------------------------------
_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 104
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 105
------------------------------------------------------------------------
_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 106
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 107
------------------------------------------------------------------------
_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 108
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 109
------------------------------------------------------------------------
_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 110
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 111
------------------------------------------------------------------------
_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 112
"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 113
------------------------------------------------------------------------
_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 114
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 115
------------------------------------------------------------------------
_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 116
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 117
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 118
------------------------------------------------------------------------
_MCHK_ON_SCREEN() _MCHK_ON_SCREEN()
------------------------------------------------------------------------
Procedure : Internal procedure called by the following functions:-
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 119
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 120
------------------------------------------------------------------------
_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 121
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 122
------------------------------------------------------------------------
_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 123
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
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 last phisical option in the list each time options
1, 3 or 5 are chosen.
.PA 124
------------------------------------------------------------------------
_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 125
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 126
------------------------------------------------------------------------
_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 127
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 128
------------------------------------------------------------------------
_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 129
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 130
------------------------------------------------------------------------
_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 131
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 132
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 133
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 134
------------------------------------------------------------------------
_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 135
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 136
------------------------------------------------------------------------
_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 137
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 138
------------------------------------------------------------------------
_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 139
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 140
------------------------------------------------------------------------
_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 141
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 142
------------------------------------------------------------------------
_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 143
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 144
------------------------------------------------------------------------
_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 145
"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 146
------------------------------------------------------------------------
_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 147
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 148
WINDOWS AND MENUS FOR TURBO PASCAL
----------------||----------------
COMMON FUNCTIONS REFERENCE SECTION
.PA 149
------------------------------------------------------------------------
_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
begin {*CHK STRUCTURE EXISTS*}
could print a message;
exit or halt;
end;
.PA 150
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 151
------------------------------------------------------------------------
_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 152
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 same....');
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 153
WINDOWS AND MENUS FOR TURBO PASCAL
-----------------||----------------
COMMON PROCEDURES REFERENCE SECTION
.PA 154
------------------------------------------------------------------------
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 155
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 156
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 157
------------------------------------------------------------------------
WMATTRIBS() WMATTRIBS()
------------------------------------------------------------------------
Procedure : Change the attributes associated with a window, menu or a
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 158
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 159
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 160
------------------------------------------------------------------------
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 161
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 162
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 163
------------------------------------------------------------------------
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 164
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 165
------------------------------------------------------------------------
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 166
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 167
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 168
------------------------------------------------------------------------
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 169
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 170
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 171
------------------------------------------------------------------------
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 172
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 173
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 174
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 175
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 176
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 177
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]
==========================================================================
.PA 178
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 179
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 180
1.4 For TP V5.X this is the table of freelist records,
each record is 8 bytes long and there is one record
for each entry or each free block, the bytes are as
follows:-
Record
BY1 : Low Byte \
BY2 : High Byte >ÄÄÄOffset \ Field 1
BY3 : Low Byte \ >ÄÄÄÄÄBlock Oragin Address.
BY4 : High Byte >ÄÄÄSegment/
BY5 : Low Byte \
BY6 : High Byte >ÄÄÄOffset \ Field 2
BY7 : Low Byte \ >ÄÄÄÄÄBlock End Address
BY8 : High byte >ÄÄÄSegment/
All the table values are in decimal, so if we take
list record number 1 for example, to get the proper
hex segment:offset address format, we do the following
Hexidecimal 20 Bit Block
Dec Hex Seg : Ofs = Address Size
BY1 : 0 0 >ÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
BY2 : 0 0 >ÄÄÄÄÄÄÄÄÄÄÄ¿ ³
BY3 : 15 0F >ÄÄÄÄÄÄ¿ ³ ³ (200F0H)
BY4 : 32 20 >ÄÄÄÄ200F : 0000 = 131312Ä¿
BY5 : 6 6 >ÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ (246H)
BY6 : 0 0 >ÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ÃÄÄ582
BY7 : 51 33 >ÄÄÄÄÄÄ¿ ³ ³ (20336H)³
BY8 : 32 20 >ÄÄÄÄ2033 : 0006 = 131894ÄÙ
The actual 20 bit address is calculated by shifting
the segment value left 4 bits (*16) and then adding
the offset.
For TP V6.X this is the table of free block
records, each record is 8 bytes long and occupies the
first 8 bytes of each free block in the programmes
heap.
For each free block, the bytes are as follows:-
Record
BY1 : Low Byte \ Field 1
BY2 : High Byte >ÄÄÄOffset \ Address Of Next
BY3 : Low Byte \ >ÄÄÄÄÄFree Block In The
BY4 : High Byte >ÄÄÄSegment/ Free Heap.
BY5 : Low Byte \
BY6 : High Byte >ÄÄÄOffset \ Field 2
BY7 : Low Byte \ >ÄÄÄÄÄSize Of Current
BY8 : High byte >ÄÄÄSegment/ Block.
.PA 181
All the table values are in decimal, so if we take
free block record number 8 for example, to get the
proper hex segment:offset address format, we do the
following
20 Bit Curr
Hexidecimal Next Blk Block
Dec Hex Seg : Ofs = Address Size
BY1 : 8 8 >ÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³
BY2 : 0 0 >ÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³
BY3 : 61 3D >ÄÄÄÄÄÄ¿ ³ ³ (233D8H) ³
BY4 : 35 23 >ÄÄÄÄ233D : 0008 =>ÄÄ144344 ³
BY5 : 8 8 >ÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³
BY6 : 0 0 >ÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³
BY7 : 36 24 >ÄÄÄÄÄÄ¿ ³ ³ (248H)
BY8 : 0 0 >ÄÄÄÄ0024 : 0008 =>ÄÄÄÄÄÄÄÄÄÄÄÄ584
The actual 20 bit address or value is calculated by
shifting the segment value left 4 bits (*16) and then
adding the offset.
NB. The TP V5.X freelist records are in reverse
order, this is because its a stack type system, last
on first off, thus record 1 from the TP V5.X printout
is the same as record 8 from the TP V6.X printout.
1.5 This sub-section only applies to TP V5.X
This is the address of the top of the freelist stack
it is important to make sure that the freelist records
have room to grow downwards, towards the top of the
heap which of course is growing upwards to meat it, so
the setting of the {$M} complier directive will have
an affect on this, for more information on how to
achieve this see the Turbo Pascal V5.X reference
manual.
1.6 This is the address of the top of the heap, or the
extent of memory that has already been allocated for a
programmes dynamic variables, the area above this is
the free memory, all or some of which, is available to
that programme for further allocation, depending on
the {$M} compiler directive settings, see the Turbo
Pascal V5.X reference guide or the Turbo Pascal V6.X
Programmers Guide for more information.
1.7 This is the address of the heap oragin, the top of the
heap minus the heap oragin gives you the total memory
that has already been used by the current programme
for its dynanmic variables.
1.8 The maxavail value is the size of the largest block of
contigous memory which is available to the current
programme either in its heap area or from its free
memory, which is above HeapPtr.
.PA 182
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 183
------------------------------------------------------------------------
WMMOVE() WMMOVE()
------------------------------------------------------------------------
Procedure : This procedure will move any window, menu or user screen
(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 184
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 185
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 186
------------------------------------------------------------------------
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 187
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 188
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 189
------------------------------------------------------------------------
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 190
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 191
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 192
------------------------------------------------------------------------
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 193
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 194
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 195
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 196
{****************}
{*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 197
{****************}
{*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 198
{****************}
{*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 199
{****************}
{*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 200
{****************}
{*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 201
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 202
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 203
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 204
------------------------------------------------------------------------
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 205
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 206
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 207
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 208
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 209
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 210
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 211
------------------------------------------------------------------------
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 212
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.
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 213
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 214
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 215
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 216
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 217
------------------------------------------------------------------------
_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 218
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 219
------------------------------------------------------------------------
_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 220
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!)
Low byte first : Colour value. High byte last : ASCII 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 221
Dec | 169 170 179 180 181 182 183 184 185 186 187 188 189 190 191
Hex | A9 AA B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
ASCII | © ª ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿
Dec | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
Hex | C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE
ASCII | À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î
Dec | 207 208 209 210 211 212 213 214 215 216 217 218
Hex | CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA
ASCII | Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú
Example : program BOX_ATTR
uses dos,crt,winmen; {*UNITS USED*}
var {*DEFINE GLOBALS*}
IDB : byte
ID : pt_wmrec
key : char
btype,bb,bf : byte
begin {*CREATE WINDOW*}
IDB := NEW_WIN(5,5,50,20,1,1,14,7,0)
ID := ID_WM[IDB]
key := '1'; {*INITIALISE KEY*}
while(key <> ' ') do {*WHILE SPACE BAR NOT*}
begin {*PRESSED *}
WOPEN(IDB)
clrscr
writeln(scr,'Press A Key For A New Window')
write(scr,'Or Space To Quit:')
while not(keypressed) do; {*WAIT FOR KEYPRESS*}
key := readkey; {*ASSIGN KEYPRESS TO KEY*}
WMCLOSE(IDB)
btype := 20; bb := 20; bf := 20
while(btype > 4)or(btype = 0) d
btype := random(4); {*ASSIGN NEW RANDOM VALS*}
while(bb > 15) d
bb := random(15)
while(bf > 15) d
bf := random(15)
_WMBOX_ATTRIBS(btype, {*CALL THE ROUTINE*}
bb,bf
ID^.tlc,ID^.trc,ID^.blc,ID^.brc
ID^.horc,ID^.verc)
end
normvideo; {*RESET TEXT ATTRIBS*}
end
.PA 222
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 223
------------------------------------------------------------------------
_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 224
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 225
------------------------------------------------------------------------
_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 226
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 227
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 228
------------------------------------------------------------------------
_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 229
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 230
------------------------------------------------------------------------
_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 231
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 232
------------------------------------------------------------------------
_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 233
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 234
------------------------------------------------------------------------
_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 235
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 same....');
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 236
------------------------------------------------------------------------
_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 237
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 238
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 239
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 240
------------------------------------------------------------------------
_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 241
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 242
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 243
------------------------------------------------------------------------
_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 244
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 245
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 246
------------------------------------------------------------------------
_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 247
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 248
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 249
P A R T
-----------------------------------------------------------------------
2
APPENDICES
.PA 250
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 251
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 252
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 253
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 t
Comments
Post a Comment