$if 0 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· PowerBASIC v3.20 ÚÄÄ´ DASoft ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· ³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ Copyright 1995 ³ DATE: 1995-10-01 ÇÄ· ³ ³ FILE NAME TINPUT .TXT º by ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÄ º º ³ ³ º Don Schullian, Jr. º º ³ ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ º º ³ A license is hereby granted to the holder to use this source code in º º ³ any program, commercial or otherwise, without receiving the express º º ³ permission of the copyright holder and without paying any royalties, º º ³ as long as this code is not distributed in any compilable format. º º ³ IE: source code files, PowerBASIC Unit files, and printed listings º º ÔÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ º ³ .................................... º ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ $endif ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ fTinput$ and fTinputM$ both use the same TINPUT_?.INC files. ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Before you get into all of this: The info in this file is vital but, despite the length of the file it is NOT difficult to understand if you don't try to make it into something more than it is. The concept was taught to me by my guru in about 30 seconds on the margin of the daily news paper! So, if I can grasp it that fast, nuff said! d;D A program is not worth much if it cannot input data and instructions from the user; how this information and data is input is one of the most important features of any program. It should be as easy and as fool-proof as possible. Your job, as programmer, is to make all this happen. As there are several different types of data one all-purpose routine just doesn't make the cut! On the other hand, to attempt to have an individual routine for each style is just too much to handle. I have come up with a happy medium: a suite of routines that allows you to call a single function from within your program. It calls a specific handler for the data style required. Sorta' like one stop shopping! There are 9 field styles. Eight of them provide specific support and the ninth is a general, all-purpose field that catches everything else. The fields are controlled by a string of data that you send. The string is loaded into a TYPE by the function before it is passed to the specific handler. As you can see the first 8 bytes of the control string fit into the TYPE but from position nine and on you can also send more data for some of the styles that require it or can use it. This area of the string is known an the MASK. Also, not all the members of the TYPE are used by all the styles and .Misc is a kind of catch-all member. Despite their comings and goings, the members hold their purpose in life throughout. Below is a generalized description for each member then a style by style discussion. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ One important thing to remember is that fTinput assumes that the ³ ³ incoming data is IN THE CORRECT FORMAT for the designated Style. ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ TYPE TinputTYPE 'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style AS STRING * 1 '³ field type ie: A,B,D,H,M,N,P,Q,T Row AS BYTE '³ screen row Col AS BYTE '³ left most screen column Cols AS BYTE '³ Nø of visible columns MustBe AS BYTE '³ > 0 if field is mandatory Cased AS BYTE '³ 0 = none 1 = UCASEed 2 = LCASEed Misc AS BYTE '³ max length of string => Cols Just AS BYTE '³ Nø of routine to call fJUSTIFY$ with END TYPE 'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 9 bytes ÃÄÄÄ .Style always indicates which field driver to use .Row always the starting screen row for the field .Col always the left-most column(s) for the field .Cols always the maximum visible columns of the field in most cases this is also the maximum length of the field .MustBe if > 0 then the field is mandatory this field is used differently by each style .Cased if 0 then no casing is done to the input if 1 then all input is UCASEd using UCASEstr if 2 then all input is LCASEd using LCASEstr .Misc used differently by each style .Just an extra byte for your use as it is NOT used by fTinput$ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ANYTHING GOES ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "A" Anything goes Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of visible columns MustBe = 0 or x > 0 if field is mandatory Cased = 0, 1 or 2 0 = NOCASING 1 = UCASEed 2 = LCASEed Misc = x maximum field length if => Cols Just = x NOT USED Mask$ = if NULL any characters accepted ELSE only chars in Mask$ eg: " 0123456789-" DATA IN : any string value from NULL to .Misc in length DATA OUT: a string of up to .Col or .Misc length As you can see this field can and will scroll through a long string of data. By using Mask$ you can restrict the keyboard input to only a few keys. ie: "0123456789-() " works well for phone numbers Another property of Alpha is that it will automatically issue a CHR$(13) if .Cols = 1 and an acceptable key is input. This allows you to use ALPHA for yes/no answers and the like, but QUERY does a better job of it. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ BLOCK O' TEXT ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "B" Block of text Row = 1 -> x top most screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of columns MustBe = NOT USED 0 is assumed Cased = NOT USED 0 is assumed Misc = x maximum number of rows of .Cols chars Just = NOT USED Mask$ = NOT USED DATA IN : any string of text DATA OUT: a string of text A simple word-wrap is employed SEE: fWrapPosF% and keys are used and acts as fTinput$ can return and as defaults from this function ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ DATES ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "D" Dates Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 8 or 10 8 is default ( + LEN(day$) ) MustBe = 0 or x > 0 if field is mandatory Cased = NOT USED Misc = NOT USED Just = NOT USED Mask$ = "Sun |Mon |Tue |Wed |Thr |Fri |Sat " NOTE: if Mask$ is used * all day names need be the same length * .Cols must include this length * D$ is _NOT_ effected The data field looks like "Mon 01-01-1995" and the user only inputs the date not the day. DATA IN : an 8 or 10 character date string in SetDateFormat style DATA OUT: same as data in If .MustBe > 0 and incoming D$ is NULL then the system's date is used ELSE Before the field exits the date entered must be a correct and legal date or a NULL field will exit with a value of SPACE$(.Cols) and display. The grey "*" resets the date to the current date "-" - 1 day (yesterday) ' these keys come in handy, along "-" - 28 days ( 4 weeks) ' with the day of the week for "-" -364 days (52 weeks) ' businesses that need to set-up "+" + 1 day (yesterday) ' appointments, meetings, etc. "+" + 28 days ( 4 weeks) ' "+" +364 days (52 weeks) ' ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ HEX & DECIMAL ASCII VALUES ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "H" Hexadecimal & decimal Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of visible columns MustBe = 0 or x > 0 if field is mandatory Cased = NOT USED Misc = x max number of chars to be edited Just = NOT USED Mask$ = NOT USED DATA IN : any string eg: "HELLO" user sees: "48h,45h,4Ch,4Ch,4Fh" DATA OUT: ditto or: "072,069,076,076,079" DATA IN : is a simple string "ABC" but is displayed as "41h,42h,43h" during editing. The user also has the use of the key to switch between HEX and DECimal display where "ABC" would become "065,066,067". During editing both HEX and DECimal are accepted and converted afterwards. Before exiting the whole mess is cleaned up and values > 255 are rejected. DATA OUT: "ABC" format The total length of the field is ( ( .Misc * 4 ) - 1 ) so .Misc is only the individual character count and not the total space required to show each character in HEX and/or DECimal format ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ MASKED ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "M" Masked input Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of visible columns (Not the mask length) MustBe = 0 or x > 0 if field is mandatory Cased = 1 1 = UCASEed input only Misc = NOT USED Just = NOT USED Mask$ = see below eg: "SS_A_N: NNN-NN-NNNN" DATA IN: a correct data string in the prescribed format or NULL DATA OUT: a correct data string or NULL if .MustBe = 0 Input is strictly controlled by use of an encoded Mask$. There are only six character types: N = mandatory (0123456789) n = optional (0123456789) and A = mandatory (A -> Z) a = optional (A -> Z) and E = mandatory > e = optional anything goes! _ preceding N,n,A,a,E, or e prints the letter __ prints a single underline character Mask$, as shown above, would present "SSAN: - - " to the user. As the numbers are filled in the cursor would automatically skip the "-"'s allowing for rapid, trouble free formatted input. The cursor can be moved around the field but will only land on character positions requiring input. Individual character deletion can also be done but, once again, only on characters in the "active" positions. Mask$ "N-NN-NNNNNN-E" would work will for ISBNs where the last position "E" could be either a number or the letter "X". Mask$ "Nn-Nn-NNnn" could be used for dates but a poor second to the individual date style ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ NUMERIC ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "N" Numbers (as values not strings) Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x length of Mask$ MustBe = 0 or x > 0 if field is mandatory Cased = NOT USED Misc = NOT USED Just = NOT USED Mask$ = "+#,###.#" DO NOT USE "+####,.#" format! DATA IN: incoming data is passed through VAL() to determine it's numeric value (if any) DATA OUT: a string suitable for conversion with VAL() Once again what is input is governed totally by Mask$. As shown above the value input can be from -9,999.99 to +9,999.99. As you can see Mask$ must be a valid format string suitable for use with USING$. If there is a leading "+" then both positive and negative numbers will be accepted else only positive numbers can be accepted. There seems to be a slight bug in v3.1 that incorrectly converts "####,.##" style masks when there are two or more commas involved in the output so use "#,###.##" just to be safe. Input for this field emulates that of a calculator; where the number "grows" from right to left and only the right most character can be erased using or . ZERO's the field's value. user presses "1" sees: 1 user presses "2" sees: 12 user presses "3" sees: 123 user presses "4" sees: 1234 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ PATH ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "P" DOS Path's, file names, etc. Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of visible columns MustBe = 0 or x > 0 if field is mandatory Cased = 2 2 = LCASEed (UCASE is assumed) Misc = x maximum field length => Cols Just = NOT USED Mask$ = ":\.?*" any or all of these chars but NO OTHERS please any character can be made available however DATA IN : any legal DOS string value from NULL to .Misc in length This field is, in fact, only a sub-set of the Alpha field. It adds to the Mask$ you send all the legal DOS characters except the 5 listed above. As you can see these 5 control the field's ability to input drive and/or path information and/or wild cards. It also defaults to upper case conversion unless you send an explicit value of 2 for .Cased Some testing is done on the input string in an attempt to forestall user mistakes but it's not perfect as no one can tell just what a user will do when given a chance ;) ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ QUERY ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "Q" Query or Questions Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 1 -> x Nø of visible columns MustBe = 0 or x > 0 if field is mandatory Cased = NOT USED UCASE only Misc = x maximum field length => Cols Just = NOT USED Mask$ = see below "MFN?|Male|Female|Not Disclosed|(Male,Female,None)" DATA IN : a single character if NULL then the left most character in Mask$ is assumed DATA OUT: one of the characters in the 1st field of Mask$ (except "?") This field acts as a mini-menu. Mask$ is cut into several pieces by the pipe "|" character. The first (left most) field are the legal selections with their long versions following in order. As the long versions are what the user sees .Cols must always represent the longest of the set. If the question mark "?" is used it must be the last selection and will cause the final field to be displayed in the event the user presses an illegal key. It can not be returned as an answer. Using Mask$ as we have it above: The user may press "M", "F", or "N" to get an acceptable answer and immediate exit from the field. Assuming the "M" is pressed the string "Male" will be printed on the screen. If, however, the "?" were pressed then "(Male, Female or None)" would be displayed for 2 seconds and would either exit upon a valid key or revert back to the original value if the time elapsed first. NOTE: an approximation of this process can be duplicated by using the Alpha field with .Cols = 1 .Cased = 1 Mask$ = "MFN" HINT: if you want your answers printed with color commands (like the first letter blue and the rest grey) use a color attribute value of ZERO for the normal attribute then embed the color command in the answer pieces ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TIMES ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Style = "T" Times Row = 1 -> x screen row Col = 1 -> x left most screen column Cols = 6 or 9 6 is default MustBe = 0 or x > 0 if field is mandatory Cased = NOT USED Misc = NOT USED Just = NOT USED Mask$ = NOT USED DATA IN: a 6 or 9 char time string eg: "HH:MM " or "HH:MM:SSx" DATA OUT: same format as data in SEE: SetTimeFormat if .MustBe > 0 and incoming D$ is NULL then the system's time will be automatically loaded input style is dependent upon the values in SetTimeFormat NOTE: times are ALWAYS edited as 24 hour clocks avoiding the "a" and "p" ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ fTinput$ ( {D$}, Control$, ExitKeys$, Nattr?, Hattr? ) fTinputM$ ( {D$}, Control$, ExitKeys$, Nattr?, Hattr?, HotSpot% ) D$ is both the incoming and exiting data if NULL then incoming data has failed some internal test or has a value of ZERO for "N"umbers Control$ is a construct of ( TinputTYPE + Mask$ ) just a quick word here just in case it isn't quite clear what we are looking for: TinputTYPE is used to convert the first 8 characters of Control$ into the separate members while Mask$ is actually cut out of the middle. LSET tINP = LEFT$( Control$, 8 ) Mask$ = MID$( Control$, 9 ) The reason this is done is to simplify storage of control strings in data files. You can, of course, use the TYPE in your code too. ExitKeys$ has 2 default keys loaded by the function: CHR$(13) = acceptance of the data CHR$(27) = disregard changes/restore original value You may add any other key(s) you wish. F-1 and F-10 would be ExitKeys$ = CHR$(0,59,0,68) Nattr? is the color attribute to use upon exiting the field Hattr? is the color attribute to use while the field is being edited HotSpot% the item number for the field being edited fTinput$ RETURNS CHR$(?) exiting key-press fTinputM$ RETURNS CHR$(?) exiting key-press NULL mouse clicked in another item of current event CHR$(255) mouse clicked in another event ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The following keys are default unless also found in ExitKeys$ delete character to the left of the cursor cursor to #1 character position move cursor 1 position left move cursor 1 position right cursor to end of data or last character position toggle insert ON/OFF SEE: fINSERTmsg% delete character under the cursor next word left next word right erase all data in the field exit field, accept new data exit field, keep original data NOTE: some of these keys have no effect on some of the field styles. ( Logic dictates here. ie: CTRL/LEFT and Numerics isn't a match ) If a key cannot be used by any field style it is simply ignored. Even though each field can handle incoming NULL values for the data I've found it best to supply whatever defaults your program may require. Even on the odd chance that the style's idea of a default value is the same as the program's there is no guarantee that the user will pass through that particular field. This would leave your data "out of shape" and may cause problems in other portions of the program. It is much safer to the data is in the proper format throughout the program than to be constantly checking it. ( Saves on the Raid bill, too... :) ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ÍÍÍÍÍ putting it all together ÍÍÍÍÍ ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ So far I've only been talking about single fields and that, no matter how good it is, is only the tip of the iceberg. Greater things are afoot here and can now be addressed. More times than not there is more that one field of data that needs to be input. One medical program I built years ago had over 2,500 fields for each record spread over 40 different screens, and without a consolidated screen input routine I would still be writing code for them all. Enter the arrays! Now no matter how many fields your screens may have, you can simply pack the data and control strings for each field into arrays and put the whole process into a single loop. By loading ExitKeys$ with , , , etc. you can easily control movement within the array. Then (and you thought I forgot) by using the .Just member of the TYPE your loop can be made to perform field specific checking, rejection and message warnings, or any one of a dozen other tasks quite simply! SEE: fJustify$ As it is a very real possibility that not all programs will require all the field styles, each style is split into a separate .INC file. TINPUT.UNT has 9 integer constants at the beginning of the file that will either include or exclude each of the TINPUT_?.INC files. This allows you to keep your programs down to their proper size without a batch of useless code laying around. The following files are required: TINPUT .TYP ' the type declaration TINPUT .UNT ' fTinput$ and all the supporting routines TINPUTM .UNT ' fTinputM$ and it's supporting routines (Mouse Aware) TINPUT_A.INC ' Alpha input TINPUT_B.INC ' Blocks TINPUT_D.INC ' Dates ( requires TINPUT_M.INC ) TINPUT_H.INC ' Hex & Decimal ( requires TINPUT_A.INC ) TINPUT_M.INC ' Masked TINPUT_N.INC ' Numbers TINPUT_P.INC ' Path ( requires TINPUT_A.INC ) TINPUT_Q.INC ' Query TINPUT_T.INC ' Times ( requires TINPUT_M.INC ) fTinput2$ ( SEG D$(), SEG F$(), SEG T?(), SEG H$(), SEG Fld% ) D$() all the incoming/outgoing data for the fields F$() all the control strings T?() if UBOUND(T?(1)) > 0 then the field numbers to be tabbed to the field numbers must be in ascending order H$() if UBOUND(H$(1)) > 0 then the help strings are printed by calling fHelpLine$ Fld% the field to start processing at This routine is ready to be input directly into your programs, but you will probably want to modify it to fit your exact needs. The "tab fields" is a handy gizmo if your program uses some monster input screens but really does very little on the small stuff and would just be a nuisance. Rip it out! Ditto with the help line. I like it (obviously) and use it constantly but..... There is no reason that you couldn't compile it and stuff it in the .PBL but I don't think I've every written 2 programs that were enough alike to do that and that is why it's an .INC file. The last little part is the use of fJustify$. The individual field routines are pretty smart to start with and you may find that fJustify$ just gets in the way. No problemo... Y is at your beck n' call! In TINPUT.DMO I've hung the whole thing together so you could see it in action, and play with it. fJustify$ is also, finally, put to some practical use in this file. It really doesn't have a lot of use in the demo but I'm sure you will get the general idea. It is not inconceivable that you could construct yet another function ( fPreJust$ ) to load default values! Two old saws come to mind: "Never write the same code twice." "There are exceptions to every rule." Last minute entry: fQueryPrint$ ( Row?, Col?, Cols?, Mask$, Answer$ ) This one was added as a good afterthought to all of this. If you remember the Query field you know that the incoming/outgoing data is a single letter that is found in the first piece of Mask$ and that the first answer is default if Answer$ is NULL. Mask$ = "YNM|Yes|No|Maybe" fQueryPrint$ will return the correct piece of Mask$ and if Row? > ZERO will use TprintCLEAR with an attribute of ZERO to print the string. While writing a small, small program for a local business I just got tired of doing the 2 or 3 lines of code necessary to make all this happen, so....... See you in TINPUT.DMO!